@@ -23,9 +23,11 @@  | 
            ||
| 23 | 23 | 
                android:theme="@style/AppTheme.NoActionBar">  | 
            
| 24 | 24 | 
                 | 
            
| 25 | 25 | 
                <activity  | 
            
| 26 | 
                - android:name=".upload.UploadActivity"  | 
            |
| 26 | 
                + android:name=".splash.SplashActivity"  | 
            |
| 27 | 27 | 
                android:configChanges="keyboardHidden|orientation|screenSize"  | 
            
| 28 | 
                - android:label="@string/app_name">  | 
            |
| 28 | 
                + android:theme="@android:style/Theme.NoTitleBar.Fullscreen"  | 
            |
| 29 | 
                + android:label="@string/app_name"  | 
            |
| 30 | 
                + android:screenOrientation="portrait">  | 
            |
| 29 | 31 | 
                 | 
            
| 30 | 32 | 
                <intent-filter>  | 
            
| 31 | 33 | 
                <action android:name="android.intent.action.MAIN" />  | 
            
                @@ -35,28 +37,44 @@  | 
            ||
| 35 | 37 | 
                </activity>  | 
            
| 36 | 38 | 
                 | 
            
| 37 | 39 | 
                <activity  | 
            
| 38 | 
                - android:name=".session.SessionActivity"  | 
            |
| 40 | 
                + android:name=".login.LoginActivity"  | 
            |
| 39 | 41 | 
                android:configChanges="keyboardHidden|orientation|screenSize"  | 
            
| 40 | 
                - android:label="@string/app_name">  | 
            |
| 42 | 
                + android:label="@string/app_name"  | 
            |
| 43 | 
                + android:screenOrientation="portrait">  | 
            |
| 44 | 
                +  | 
            |
| 41 | 45 | 
                </activity>  | 
            
| 42 | 46 | 
                 | 
            
| 43 | 47 | 
                <activity  | 
            
| 44 | 
                - android:name=".qrcode.QRCaptureActivity"  | 
            |
| 48 | 
                + android:name=".upload.UploadActivity"  | 
            |
| 45 | 49 | 
                android:configChanges="keyboardHidden|orientation|screenSize"  | 
            
| 46 | 
                - android:label="@string/app_name">  | 
            |
| 50 | 
                + android:label="@string/app_name"  | 
            |
| 51 | 
                + android:screenOrientation="portrait">  | 
            |
| 52 | 
                +  | 
            |
| 47 | 53 | 
                </activity>  | 
            
| 48 | 54 | 
                 | 
            
| 49 | 55 | 
                <activity  | 
            
| 50 | 
                - android:name=".briefs.BriefsActivity"  | 
            |
| 51 | 
                - android:configChanges="keyboardHidden|orientation|screenSize"  | 
            |
| 52 | 
                - android:label="@string/app_name">  | 
            |
| 53 | 
                - </activity>  | 
            |
| 56 | 
                + android:name=".session.SessionActivity"  | 
            |
| 57 | 
                + android:configChanges="keyboardHidden|orientation|screenSize"  | 
            |
| 58 | 
                + android:label="@string/app_name"  | 
            |
| 59 | 
                + android:screenOrientation="portrait"></activity>  | 
            |
| 60 | 
                +  | 
            |
| 61 | 
                + <activity  | 
            |
| 62 | 
                + android:name=".qrcode.QRCaptureActivity"  | 
            |
| 63 | 
                + android:configChanges="keyboardHidden|orientation|screenSize"  | 
            |
| 64 | 
                + android:label="@string/app_name"  | 
            |
| 65 | 
                + android:screenOrientation="portrait"></activity>  | 
            |
| 66 | 
                +  | 
            |
| 67 | 
                + <activity  | 
            |
| 68 | 
                + android:name=".briefs.BriefsActivity"  | 
            |
| 69 | 
                + android:configChanges="keyboardHidden|orientation|screenSize"  | 
            |
| 70 | 
                + android:label="@string/app_name"  | 
            |
| 71 | 
                + android:screenOrientation="portrait"></activity>  | 
            |
| 54 | 72 | 
                 | 
            
| 55 | 73 | 
                <activity  | 
            
| 56 | 74 | 
                android:name=".settings.SettingsActivity"  | 
            
| 57 | 75 | 
                android:configChanges="keyboardHidden|orientation|screenSize"  | 
            
| 58 | 
                - android:label="@string/app_name">  | 
            |
| 59 | 
                - </activity>  | 
            |
| 76 | 
                + android:label="@string/app_name"  | 
            |
| 77 | 
                + android:screenOrientation="portrait"></activity>  | 
            |
| 60 | 78 | 
                 | 
            
| 61 | 79 | 
                </application>  | 
            
| 62 | 80 | 
                 | 
            
                @@ -0,0 +1,67 @@  | 
            ||
| 1 | 
                +package ai.pai.lensman.base;  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +import android.os.Bundle;  | 
            |
| 4 | 
                +import android.support.v7.app.AppCompatActivity;  | 
            |
| 5 | 
                +import android.view.View;  | 
            |
| 6 | 
                +import android.widget.Toast;  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +import com.android.common.utils.NetworkUtil;  | 
            |
| 9 | 
                +import com.android.views.swipebacklayout.SwipeBackActivityBase;  | 
            |
| 10 | 
                +import com.android.views.swipebacklayout.SwipeBackActivityHelper;  | 
            |
| 11 | 
                +import com.android.views.swipebacklayout.SwipeBackLayout;  | 
            |
| 12 | 
                +import com.android.views.swipebacklayout.Utils;  | 
            |
| 13 | 
                +  | 
            |
| 14 | 
                +import ai.pai.lensman.R;  | 
            |
| 15 | 
                +  | 
            |
| 16 | 
                +/**  | 
            |
| 17 | 
                + * Created by chengzhenyu on 2015/12/2.  | 
            |
| 18 | 
                + */  | 
            |
| 19 | 
                +public class BaseActivity extends AppCompatActivity implements SwipeBackActivityBase {
               | 
            |
| 20 | 
                +  | 
            |
| 21 | 
                + protected String TAG ;  | 
            |
| 22 | 
                +  | 
            |
| 23 | 
                + private SwipeBackActivityHelper mHelper;  | 
            |
| 24 | 
                +  | 
            |
| 25 | 
                + @Override  | 
            |
| 26 | 
                +    protected void onCreate(Bundle savedInstanceState) {
               | 
            |
| 27 | 
                + super.onCreate(savedInstanceState);  | 
            |
| 28 | 
                + TAG = getClass().getSimpleName();  | 
            |
| 29 | 
                + mHelper = new SwipeBackActivityHelper(this);  | 
            |
| 30 | 
                + mHelper.onActivityCreate();  | 
            |
| 31 | 
                +        if(!NetworkUtil.isNetworkConnected(this)){
               | 
            |
| 32 | 
                + Toast.makeText(this, R.string.network_disconnect,Toast.LENGTH_SHORT).show();  | 
            |
| 33 | 
                + }  | 
            |
| 34 | 
                + }  | 
            |
| 35 | 
                +  | 
            |
| 36 | 
                + @Override  | 
            |
| 37 | 
                +    protected void onPostCreate(Bundle savedInstanceState) {
               | 
            |
| 38 | 
                + super.onPostCreate(savedInstanceState);  | 
            |
| 39 | 
                + mHelper.onPostCreate();  | 
            |
| 40 | 
                + }  | 
            |
| 41 | 
                +  | 
            |
| 42 | 
                + @Override  | 
            |
| 43 | 
                +    public View findViewById(int id) {
               | 
            |
| 44 | 
                + View v = super.findViewById(id);  | 
            |
| 45 | 
                + if (v == null && mHelper != null)  | 
            |
| 46 | 
                + return mHelper.findViewById(id);  | 
            |
| 47 | 
                + return v;  | 
            |
| 48 | 
                + }  | 
            |
| 49 | 
                +  | 
            |
| 50 | 
                + @Override  | 
            |
| 51 | 
                +    public SwipeBackLayout getSwipeBackLayout() {
               | 
            |
| 52 | 
                + return mHelper.getSwipeBackLayout();  | 
            |
| 53 | 
                + }  | 
            |
| 54 | 
                +  | 
            |
| 55 | 
                + @Override  | 
            |
| 56 | 
                +    public void setSwipeBackEnable(boolean enable) {
               | 
            |
| 57 | 
                + getSwipeBackLayout().setEnableGesture(enable);  | 
            |
| 58 | 
                + }  | 
            |
| 59 | 
                +  | 
            |
| 60 | 
                + @Override  | 
            |
| 61 | 
                +    public void scrollToFinishActivity() {
               | 
            |
| 62 | 
                + Utils.convertActivityToTranslucent(this);  | 
            |
| 63 | 
                + getSwipeBackLayout().scrollToFinishActivity();  | 
            |
| 64 | 
                + }  | 
            |
| 65 | 
                +  | 
            |
| 66 | 
                +  | 
            |
| 67 | 
                +}  | 
            
                @@ -22,8 +22,8 @@ public final class ApiClient {
               | 
            ||
| 22 | 22 | 
                private static final OkHttpClient client = new OkHttpClient.Builder()  | 
            
| 23 | 23 | 
                .retryOnConnectionFailure(true)  | 
            
| 24 | 24 | 
                .connectTimeout(10, TimeUnit.SECONDS)  | 
            
| 25 | 
                - .addInterceptor(createUserAgentInterceptor())  | 
            |
| 26 | 
                - .addInterceptor(createHttpLoggingInterceptor())  | 
            |
| 25 | 
                +// .addInterceptor(createUserAgentInterceptor())  | 
            |
| 26 | 
                +// .addInterceptor(createHttpLoggingInterceptor())  | 
            |
| 27 | 27 | 
                .build();  | 
            
| 28 | 28 | 
                 | 
            
| 29 | 29 | 
                public static final Gson gson = new GsonBuilder().create();  | 
            
                @@ -5,21 +5,26 @@ import java.util.List;  | 
            ||
| 5 | 5 | 
                import ai.pai.lensman.session.PhotoBean;  | 
            
| 6 | 6 | 
                import retrofit2.Call;  | 
            
| 7 | 7 | 
                import retrofit2.http.Field;  | 
            
| 8 | 
                +import retrofit2.http.FormUrlEncoded;  | 
            |
| 8 | 9 | 
                import retrofit2.http.POST;  | 
            
| 9 | 10 | 
                 | 
            
| 10 | 11 | 
                 public interface ApiService {
               | 
            
| 11 | 12 | 
                 | 
            
| 12 | 13 | 
                 | 
            
| 13 | 14 | 
                     @POST("session_start")
               | 
            
| 15 | 
                + @FormUrlEncoded  | 
            |
| 14 | 16 | 
                     Call<String> startNewSession(@Field("session") String sessionId ,@Field("lensman") String lensmanId);
               | 
            
| 15 | 17 | 
                 | 
            
| 16 | 18 | 
                     @POST("session_end")
               | 
            
| 19 | 
                + @FormUrlEncoded  | 
            |
| 17 | 20 | 
                     Call<String> endSession(@Field("session") String sessionId, @Field("lensman") String lensmanId);
               | 
            
| 18 | 21 | 
                 | 
            
| 19 | 22 | 
                     @POST("fetch_thumbnail")
               | 
            
| 23 | 
                + @FormUrlEncoded  | 
            |
| 20 | 24 | 
                     Call<List<PhotoBean>> fetchSessionThumbnails(@Field("session") String sessionId, @Field("lensman") String lensmanId);
               | 
            
| 21 | 25 | 
                 | 
            
| 22 | 26 | 
                     @POST("fetch_origin")
               | 
            
| 27 | 
                + @FormUrlEncoded  | 
            |
| 23 | 28 | 
                     Call<String> fetchSessionOriginPhoto(@Field("session") String sessionId, @Field("lensman") String lensmanId, @Field("name") String name);
               | 
            
| 24 | 29 | 
                 | 
            
| 25 | 30 | 
                 | 
            
                @@ -3,14 +3,14 @@ package ai.pai.lensman.briefs;  | 
            ||
| 3 | 3 | 
                import android.content.Intent;  | 
            
| 4 | 4 | 
                import android.os.Bundle;  | 
            
| 5 | 5 | 
                import android.support.annotation.Nullable;  | 
            
| 6 | 
                -import android.support.v7.app.AppCompatActivity;  | 
            |
| 7 | 6 | 
                 | 
            
| 8 | 7 | 
                import ai.pai.lensman.R;  | 
            
| 8 | 
                +import ai.pai.lensman.base.BaseActivity;  | 
            |
| 9 | 9 | 
                import ai.pai.lensman.settings.SettingsActivity;  | 
            
| 10 | 10 | 
                import butterknife.ButterKnife;  | 
            
| 11 | 11 | 
                import butterknife.OnClick;  | 
            
| 12 | 12 | 
                 | 
            
| 13 | 
                -public class BriefsActivity extends AppCompatActivity{
               | 
            |
| 13 | 
                +public class BriefsActivity extends BaseActivity{
               | 
            |
| 14 | 14 | 
                 | 
            
| 15 | 15 | 
                @Override  | 
            
| 16 | 16 | 
                     protected void onCreate(@Nullable Bundle savedInstanceState) {
               | 
            
                @@ -0,0 +1,29 @@  | 
            ||
| 1 | 
                +package ai.pai.lensman.login;  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +import android.content.Intent;  | 
            |
| 4 | 
                +import android.os.Bundle;  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +import ai.pai.lensman.R;  | 
            |
| 7 | 
                +import ai.pai.lensman.base.BaseActivity;  | 
            |
| 8 | 
                +import ai.pai.lensman.db.Preferences;  | 
            |
| 9 | 
                +import ai.pai.lensman.upload.UploadActivity;  | 
            |
| 10 | 
                +import butterknife.ButterKnife;  | 
            |
| 11 | 
                +import butterknife.OnClick;  | 
            |
| 12 | 
                +  | 
            |
| 13 | 
                +public class LoginActivity extends BaseActivity {
               | 
            |
| 14 | 
                +  | 
            |
| 15 | 
                + @Override  | 
            |
| 16 | 
                +    protected void onCreate(Bundle savedInstanceState) {
               | 
            |
| 17 | 
                + super.onCreate(savedInstanceState);  | 
            |
| 18 | 
                + setContentView(R.layout.activity_login);  | 
            |
| 19 | 
                + ButterKnife.bind(this);  | 
            |
| 20 | 
                + }  | 
            |
| 21 | 
                +  | 
            |
| 22 | 
                + @OnClick(R.id.btn_login)  | 
            |
| 23 | 
                +    public void login(){
               | 
            |
| 24 | 
                +        Preferences.getInstance(this).setLensManId("hafihafhHDFA");
               | 
            |
| 25 | 
                + startActivity(new Intent(this, UploadActivity.class));  | 
            |
| 26 | 
                + finish();  | 
            |
| 27 | 
                + }  | 
            |
| 28 | 
                +  | 
            |
| 29 | 
                +}  | 
            
                @@ -24,7 +24,6 @@ import android.graphics.BitmapFactory;  | 
            ||
| 24 | 24 | 
                import android.graphics.Rect;  | 
            
| 25 | 25 | 
                import android.os.Bundle;  | 
            
| 26 | 26 | 
                import android.os.Handler;  | 
            
| 27 | 
                -import android.support.v4.app.FragmentActivity;  | 
            |
| 28 | 27 | 
                import android.text.TextUtils;  | 
            
| 29 | 28 | 
                import android.util.Log;  | 
            
| 30 | 29 | 
                import android.view.SurfaceHolder;  | 
            
                @@ -51,6 +50,7 @@ import java.lang.reflect.Field;  | 
            ||
| 51 | 50 | 
                import java.util.Hashtable;  | 
            
| 52 | 51 | 
                 | 
            
| 53 | 52 | 
                import ai.pai.lensman.R;  | 
            
| 53 | 
                +import ai.pai.lensman.base.BaseActivity;  | 
            |
| 54 | 54 | 
                import ai.pai.lensman.utils.SystemUtils;  | 
            
| 55 | 55 | 
                import butterknife.BindView;  | 
            
| 56 | 56 | 
                import butterknife.ButterKnife;  | 
            
                @@ -65,7 +65,7 @@ import butterknife.ButterKnife;  | 
            ||
| 65 | 65 | 
                * @author dswitkin@google.com (Daniel Switkin)  | 
            
| 66 | 66 | 
                * @author Sean Owen  | 
            
| 67 | 67 | 
                */  | 
            
| 68 | 
                -public class QRCaptureActivity extends FragmentActivity implements SurfaceHolder.Callback,  | 
            |
| 68 | 
                +public class QRCaptureActivity extends BaseActivity implements SurfaceHolder.Callback,  | 
            |
| 69 | 69 | 
                         View.OnClickListener {
               | 
            
| 70 | 70 | 
                 | 
            
| 71 | 71 | 
                private static final String TAG = "QRCaptureActivity";  | 
            
                @@ -1,4 +1,4 @@  | 
            ||
| 1 | 
                -package ai.pai.lensman.uploadservice;  | 
            |
| 1 | 
                +package ai.pai.lensman.service;  | 
            |
| 2 | 2 | 
                 | 
            
| 3 | 3 | 
                import android.os.Environment;  | 
            
| 4 | 4 | 
                 | 
            
                @@ -1,4 +1,4 @@  | 
            ||
| 1 | 
                -package ai.pai.lensman.uploadservice;  | 
            |
| 1 | 
                +package ai.pai.lensman.service;  | 
            |
| 2 | 2 | 
                 | 
            
| 3 | 3 | 
                import android.graphics.Bitmap;  | 
            
| 4 | 4 | 
                import android.graphics.BitmapFactory;  | 
            
                @@ -1,4 +1,4 @@  | 
            ||
| 1 | 
                -package ai.pai.lensman.uploadservice;  | 
            |
| 1 | 
                +package ai.pai.lensman.service;  | 
            |
| 2 | 2 | 
                 | 
            
| 3 | 3 | 
                import android.graphics.Bitmap;  | 
            
| 4 | 4 | 
                import android.graphics.BitmapFactory;  | 
            
                @@ -0,0 +1,128 @@  | 
            ||
| 1 | 
                +package ai.pai.lensman.service;  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +import android.app.IntentService;  | 
            |
| 5 | 
                +import android.content.Intent;  | 
            |
| 6 | 
                +import android.content.pm.PackageInfo;  | 
            |
| 7 | 
                +import android.net.Uri;  | 
            |
| 8 | 
                +import android.os.Handler;  | 
            |
| 9 | 
                +import android.os.Looper;  | 
            |
| 10 | 
                +import android.widget.Toast;  | 
            |
| 11 | 
                +  | 
            |
| 12 | 
                +import com.android.common.http.HttpUtils;  | 
            |
| 13 | 
                +import com.android.common.utils.JSONParseUtils;  | 
            |
| 14 | 
                +import com.android.common.utils.LogHelper;  | 
            |
| 15 | 
                +  | 
            |
| 16 | 
                +import org.json.JSONObject;  | 
            |
| 17 | 
                +  | 
            |
| 18 | 
                +import java.io.File;  | 
            |
| 19 | 
                +import java.io.FileOutputStream;  | 
            |
| 20 | 
                +import java.io.InputStream;  | 
            |
| 21 | 
                +import java.net.HttpURLConnection;  | 
            |
| 22 | 
                +import java.net.URL;  | 
            |
| 23 | 
                +  | 
            |
| 24 | 
                +import ai.pai.lensman.R;  | 
            |
| 25 | 
                +import ai.pai.lensman.utils.UrlContainer;  | 
            |
| 26 | 
                +  | 
            |
| 27 | 
                +  | 
            |
| 28 | 
                +public class UpgradeService extends IntentService {
               | 
            |
| 29 | 
                +  | 
            |
| 30 | 
                + private static final String TAG = "UpgradeService";  | 
            |
| 31 | 
                + private Handler handler;  | 
            |
| 32 | 
                +  | 
            |
| 33 | 
                +    public UpgradeService() {
               | 
            |
| 34 | 
                + super(TAG);  | 
            |
| 35 | 
                + handler = new Handler(Looper.getMainLooper());  | 
            |
| 36 | 
                + }  | 
            |
| 37 | 
                +  | 
            |
| 38 | 
                + @Override  | 
            |
| 39 | 
                +    protected void onHandleIntent(Intent intent) {
               | 
            |
| 40 | 
                +        boolean isMuteUpdate = intent.getBooleanExtra("isMuteUpdate",true);
               | 
            |
| 41 | 
                +        try{
               | 
            |
| 42 | 
                + String result = HttpUtils.doHttpPost(UrlContainer.CHECK_UPDATE_URL,null);  | 
            |
| 43 | 
                + LogHelper.d(TAG,"检查更新结果"+result);  | 
            |
| 44 | 
                + JSONObject json = new JSONObject(result);  | 
            |
| 45 | 
                +            int status = json.getInt("status");
               | 
            |
| 46 | 
                +            if(status!=200){
               | 
            |
| 47 | 
                + LogHelper.d(TAG,"检查更新失败");  | 
            |
| 48 | 
                +                if(!isMuteUpdate){
               | 
            |
| 49 | 
                +                    handler.post(new Runnable() {
               | 
            |
| 50 | 
                + @Override  | 
            |
| 51 | 
                +                        public void run() {
               | 
            |
| 52 | 
                + Toast.makeText(getApplicationContext(), R.string.check_version_fail,Toast.LENGTH_SHORT).show();  | 
            |
| 53 | 
                + }  | 
            |
| 54 | 
                + });  | 
            |
| 55 | 
                + }  | 
            |
| 56 | 
                + return;  | 
            |
| 57 | 
                + }  | 
            |
| 58 | 
                +            JSONObject data = json.getJSONObject("data");
               | 
            |
| 59 | 
                +            JSONObject appInfo = data.getJSONObject("appinfo");
               | 
            |
| 60 | 
                +            String latestVersionCode = JSONParseUtils.getJSONString(appInfo.getString("latest_version_code"));
               | 
            |
| 61 | 
                + int versionCode = Integer.parseInt(latestVersionCode);  | 
            |
| 62 | 
                + PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(),0);  | 
            |
| 63 | 
                +            if(versionCode<=packageInfo.versionCode){
               | 
            |
| 64 | 
                + LogHelper.d(TAG,"不需要更新");  | 
            |
| 65 | 
                +                if(!isMuteUpdate){
               | 
            |
| 66 | 
                +                    handler.post(new Runnable() {
               | 
            |
| 67 | 
                + @Override  | 
            |
| 68 | 
                +                        public void run() {
               | 
            |
| 69 | 
                + Toast.makeText(getApplicationContext(), R.string.current_version_is_latest,Toast.LENGTH_SHORT).show();  | 
            |
| 70 | 
                + }  | 
            |
| 71 | 
                + });  | 
            |
| 72 | 
                + }  | 
            |
| 73 | 
                + return;  | 
            |
| 74 | 
                + }  | 
            |
| 75 | 
                +            String latestVersionUrl = JSONParseUtils.getJSONString(appInfo.getString("latest_url"));
               | 
            |
| 76 | 
                + URL url = new URL(latestVersionUrl);  | 
            |
| 77 | 
                + HttpURLConnection conn = (HttpURLConnection)url.openConnection();  | 
            |
| 78 | 
                +            conn.setRequestMethod("GET");
               | 
            |
| 79 | 
                + conn.setReadTimeout(10000);  | 
            |
| 80 | 
                + conn.setConnectTimeout(10000);  | 
            |
| 81 | 
                +            conn.setRequestProperty("accept", "*/*");
               | 
            |
| 82 | 
                + conn.connect();  | 
            |
| 83 | 
                +  | 
            |
| 84 | 
                + File dir = new File(Constants.APP_TEMP_DIR);  | 
            |
| 85 | 
                + dir.mkdirs();  | 
            |
| 86 | 
                + File file = new File(dir,"paiai"+System.currentTimeMillis()+".apk");  | 
            |
| 87 | 
                + LogHelper.d(TAG,"需要更新,开始下载,下载到:"+file.getAbsolutePath());  | 
            |
| 88 | 
                +            if(!isMuteUpdate){
               | 
            |
| 89 | 
                + Toast.makeText(this, R.string.new_version_found,Toast.LENGTH_SHORT).show();  | 
            |
| 90 | 
                + }  | 
            |
| 91 | 
                +            if(!file.exists()){
               | 
            |
| 92 | 
                + file.createNewFile();  | 
            |
| 93 | 
                + }  | 
            |
| 94 | 
                + FileOutputStream out = new FileOutputStream(file);  | 
            |
| 95 | 
                + InputStream in =conn.getInputStream();  | 
            |
| 96 | 
                + int bufSize = 8192;  | 
            |
| 97 | 
                + int readLen = 0;  | 
            |
| 98 | 
                + int pos = 0;  | 
            |
| 99 | 
                + byte[] buffer = new byte[bufSize];  | 
            |
| 100 | 
                +            while((readLen=in.read(buffer,pos,bufSize-pos))!=-1){
               | 
            |
| 101 | 
                + out.write(buffer,pos,readLen);  | 
            |
| 102 | 
                + pos+=readLen;  | 
            |
| 103 | 
                +                if(pos>=bufSize){
               | 
            |
| 104 | 
                + pos = 0;  | 
            |
| 105 | 
                + }  | 
            |
| 106 | 
                + }  | 
            |
| 107 | 
                + out.flush();  | 
            |
| 108 | 
                + in.close();  | 
            |
| 109 | 
                + out.close();  | 
            |
| 110 | 
                + conn.disconnect();  | 
            |
| 111 | 
                + Intent installIntent = new Intent();  | 
            |
| 112 | 
                + installIntent.setAction(Intent.ACTION_VIEW);  | 
            |
| 113 | 
                + installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  | 
            |
| 114 | 
                + installIntent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");  | 
            |
| 115 | 
                + startActivity(installIntent);  | 
            |
| 116 | 
                +        }catch (Exception e){
               | 
            |
| 117 | 
                +            if(!isMuteUpdate){
               | 
            |
| 118 | 
                +                handler.post(new Runnable() {
               | 
            |
| 119 | 
                + @Override  | 
            |
| 120 | 
                +                    public void run() {
               | 
            |
| 121 | 
                + Toast.makeText(getApplicationContext(), R.string.check_version_fail,Toast.LENGTH_SHORT).show();  | 
            |
| 122 | 
                + }  | 
            |
| 123 | 
                + });  | 
            |
| 124 | 
                + }  | 
            |
| 125 | 
                + }  | 
            |
| 126 | 
                + }  | 
            |
| 127 | 
                +  | 
            |
| 128 | 
                +}  | 
            
                @@ -1,4 +1,4 @@  | 
            ||
| 1 | 
                -package ai.pai.lensman.uploadservice;  | 
            |
| 1 | 
                +package ai.pai.lensman.service;  | 
            |
| 2 | 2 | 
                 | 
            
| 3 | 3 | 
                import android.content.Context;  | 
            
| 4 | 4 | 
                import android.os.AsyncTask;  | 
            
                @@ -39,7 +39,7 @@ public class UploadTask extends AsyncTask<String,Integer,Boolean> {
               | 
            ||
| 39 | 39 | 
                             if(photo.exists() &&photo.isFile()){
               | 
            
| 40 | 40 | 
                PhotoUploadUtils photoUploadUtils = new PhotoUploadUtils(UrlContainer.HOME_PHOTO_URL+"?timestamp="+System.currentTimeMillis());  | 
            
| 41 | 41 | 
                                 photoUploadUtils.addFileParameter("photo", photo);
               | 
            
| 42 | 
                -                photoUploadUtils.addTextParameter("user_id", Preferences.getInstance(context).getUserId());
               | 
            |
| 42 | 
                +                photoUploadUtils.addTextParameter("user_id", Preferences.getInstance(context).getLensManId());
               | 
            |
| 43 | 43 | 
                                 photoUploadUtils.addTextParameter("group_id", groupId);
               | 
            
| 44 | 44 | 
                                 photoUploadUtils.addTextParameter("nickname", Preferences.getInstance(context).getUserName());
               | 
            
| 45 | 45 | 
                String result=new String(photoUploadUtils.send(),"UTF-8");  | 
            
                @@ -3,20 +3,20 @@ package ai.pai.lensman.session;  | 
            ||
| 3 | 3 | 
                import android.app.Activity;  | 
            
| 4 | 4 | 
                import android.content.Intent;  | 
            
| 5 | 5 | 
                import android.os.Bundle;  | 
            
| 6 | 
                -import android.support.v7.app.AppCompatActivity;  | 
            |
| 7 | 6 | 
                import android.support.v7.widget.LinearLayoutManager;  | 
            
| 8 | 7 | 
                import android.support.v7.widget.RecyclerView;  | 
            
| 9 | 8 | 
                import android.view.View;  | 
            
| 10 | 9 | 
                import android.widget.TextView;  | 
            
| 11 | 10 | 
                 | 
            
| 12 | 11 | 
                import ai.pai.lensman.R;  | 
            
| 12 | 
                +import ai.pai.lensman.base.BaseActivity;  | 
            |
| 13 | 13 | 
                import ai.pai.lensman.qrcode.QRCaptureActivity;  | 
            
| 14 | 14 | 
                import ai.pai.lensman.upload.SessionBean;  | 
            
| 15 | 15 | 
                import butterknife.BindView;  | 
            
| 16 | 16 | 
                import butterknife.ButterKnife;  | 
            
| 17 | 17 | 
                import butterknife.OnClick;  | 
            
| 18 | 18 | 
                 | 
            
| 19 | 
                -public class SessionActivity extends AppCompatActivity implements SessionContract.SessionView {
               | 
            |
| 19 | 
                +public class SessionActivity extends BaseActivity implements SessionContract.SessionView {
               | 
            |
| 20 | 20 | 
                 | 
            
| 21 | 21 | 
                @BindView(R.id.icon_no_data) View noPhotoLayout;  | 
            
| 22 | 22 | 
                @BindView(R.id.title_bar_middle_txt) TextView titleTextView;  | 
            
                @@ -5,13 +5,14 @@ import android.support.annotation.Nullable;  | 
            ||
| 5 | 5 | 
                import android.support.v7.app.AppCompatActivity;  | 
            
| 6 | 6 | 
                 | 
            
| 7 | 7 | 
                import ai.pai.lensman.R;  | 
            
| 8 | 
                +import ai.pai.lensman.base.BaseActivity;  | 
            |
| 8 | 9 | 
                import butterknife.ButterKnife;  | 
            
| 9 | 10 | 
                import butterknife.OnClick;  | 
            
| 10 | 11 | 
                 | 
            
| 11 | 12 | 
                /**  | 
            
| 12 | 13 | 
                * Created by chengzhenyu on 2016/7/21.  | 
            
| 13 | 14 | 
                */  | 
            
| 14 | 
                -public class SettingsActivity extends AppCompatActivity {
               | 
            |
| 15 | 
                +public class SettingsActivity extends BaseActivity {
               | 
            |
| 15 | 16 | 
                 | 
            
| 16 | 17 | 
                 | 
            
| 17 | 18 | 
                @Override  | 
            
                @@ -0,0 +1,70 @@  | 
            ||
| 1 | 
                +package ai.pai.lensman.splash;  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +import android.content.Intent;  | 
            |
| 4 | 
                +import android.os.Bundle;  | 
            |
| 5 | 
                +import android.os.Handler;  | 
            |
| 6 | 
                +import android.support.v4.app.FragmentActivity;  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +import com.android.common.utils.NetworkUtil;  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                +import java.text.SimpleDateFormat;  | 
            |
| 11 | 
                +import java.util.Date;  | 
            |
| 12 | 
                +  | 
            |
| 13 | 
                +import ai.pai.lensman.R;  | 
            |
| 14 | 
                +import ai.pai.lensman.db.Preferences;  | 
            |
| 15 | 
                +import ai.pai.lensman.login.LoginActivity;  | 
            |
| 16 | 
                +import ai.pai.lensman.service.UpgradeService;  | 
            |
| 17 | 
                +import ai.pai.lensman.upload.UploadActivity;  | 
            |
| 18 | 
                +  | 
            |
| 19 | 
                +public class SplashActivity extends FragmentActivity {
               | 
            |
| 20 | 
                +  | 
            |
| 21 | 
                + private Handler mHandler;  | 
            |
| 22 | 
                + private static final int NORMAL_DELAY_TIME = 1500;  | 
            |
| 23 | 
                +  | 
            |
| 24 | 
                + @Override  | 
            |
| 25 | 
                +    protected void onCreate(Bundle savedInstanceState) {
               | 
            |
| 26 | 
                + super.onCreate(savedInstanceState);  | 
            |
| 27 | 
                + setContentView(R.layout.activity_splash);  | 
            |
| 28 | 
                + mHandler = new Handler();  | 
            |
| 29 | 
                + }  | 
            |
| 30 | 
                +  | 
            |
| 31 | 
                + @Override  | 
            |
| 32 | 
                +    protected void onResume() {
               | 
            |
| 33 | 
                + super.onResume();  | 
            |
| 34 | 
                + checkUpdateAndSplash();  | 
            |
| 35 | 
                +        mHandler.postDelayed(new Runnable() {
               | 
            |
| 36 | 
                + @Override  | 
            |
| 37 | 
                +            public void run() {
               | 
            |
| 38 | 
                + Intent intent ;  | 
            |
| 39 | 
                +                if(Preferences.getInstance(getApplicationContext()).getLensManId().isEmpty()){
               | 
            |
| 40 | 
                + intent = new Intent(SplashActivity.this, LoginActivity.class);  | 
            |
| 41 | 
                +                }else{
               | 
            |
| 42 | 
                + intent = new Intent(SplashActivity.this, UploadActivity.class);  | 
            |
| 43 | 
                + }  | 
            |
| 44 | 
                + startActivity(intent);  | 
            |
| 45 | 
                + finish();  | 
            |
| 46 | 
                + }  | 
            |
| 47 | 
                + }, NORMAL_DELAY_TIME);  | 
            |
| 48 | 
                + }  | 
            |
| 49 | 
                +  | 
            |
| 50 | 
                + @Override  | 
            |
| 51 | 
                +    protected void onStop() {
               | 
            |
| 52 | 
                + super.onStop();  | 
            |
| 53 | 
                + mHandler.removeCallbacksAndMessages(null);  | 
            |
| 54 | 
                + }  | 
            |
| 55 | 
                +  | 
            |
| 56 | 
                +    private void checkUpdateAndSplash() {
               | 
            |
| 57 | 
                +        try {
               | 
            |
| 58 | 
                +            String curDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
               | 
            |
| 59 | 
                +            if (!Preferences.getInstance(this).getLastRunDate().equals(curDate) && NetworkUtil.isWifiConnected(this)) {
               | 
            |
| 60 | 
                + Preferences.getInstance(this).setLastRunDate(curDate);  | 
            |
| 61 | 
                + Intent intent = new Intent(this, UpgradeService.class);  | 
            |
| 62 | 
                + startService(intent);  | 
            |
| 63 | 
                + }  | 
            |
| 64 | 
                +        } catch (Exception e) {
               | 
            |
| 65 | 
                + e.printStackTrace();  | 
            |
| 66 | 
                + }  | 
            |
| 67 | 
                + }  | 
            |
| 68 | 
                +  | 
            |
| 69 | 
                +  | 
            |
| 70 | 
                +}  | 
            
                @@ -2,7 +2,6 @@ package ai.pai.lensman.upload;  | 
            ||
| 2 | 2 | 
                 | 
            
| 3 | 3 | 
                import android.content.Intent;  | 
            
| 4 | 4 | 
                import android.os.Bundle;  | 
            
| 5 | 
                -import android.support.v7.app.AppCompatActivity;  | 
            |
| 6 | 5 | 
                import android.support.v7.widget.GridLayoutManager;  | 
            
| 7 | 6 | 
                import android.support.v7.widget.LinearLayoutManager;  | 
            
| 8 | 7 | 
                import android.support.v7.widget.RecyclerView;  | 
            
                @@ -13,12 +12,13 @@ import android.widget.TextView;  | 
            ||
| 13 | 12 | 
                import java.util.ArrayList;  | 
            
| 14 | 13 | 
                 | 
            
| 15 | 14 | 
                import ai.pai.lensman.R;  | 
            
| 15 | 
                +import ai.pai.lensman.base.BaseActivity;  | 
            |
| 16 | 16 | 
                import ai.pai.lensman.briefs.BriefsActivity;  | 
            
| 17 | 17 | 
                import butterknife.BindView;  | 
            
| 18 | 18 | 
                import butterknife.ButterKnife;  | 
            
| 19 | 19 | 
                import butterknife.OnClick;  | 
            
| 20 | 20 | 
                 | 
            
| 21 | 
                -public class UploadActivity extends AppCompatActivity implements UploadContract.UploadView{
               | 
            |
| 21 | 
                +public class UploadActivity extends BaseActivity implements UploadContract.UploadView{
               | 
            |
| 22 | 22 | 
                 | 
            
| 23 | 23 | 
                @BindView(R.id.tv_bt_status) TextView btStatusTextView;  | 
            
| 24 | 24 | 
                @BindView(R.id.iv_bt_status) ImageView btStatusImageView;  | 
            
                @@ -9,4 +9,6 @@ public class UrlContainer {
               | 
            ||
| 9 | 9 | 
                 | 
            
| 10 | 10 | 
                public static final String HOME_PHOTO_URL = HOST_URL+"pai2/home";  | 
            
| 11 | 11 | 
                 | 
            
| 12 | 
                + public static final String CHECK_UPDATE_URL = HOST_URL+"op/upgrade";  | 
            |
| 13 | 
                +  | 
            |
| 12 | 14 | 
                }  | 
            
                @@ -1,6 +1,16 @@  | 
            ||
| 1 | 1 | 
                <?xml version="1.0" encoding="utf-8"?>  | 
            
| 2 | 2 | 
                <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  | 
            
| 3 | 3 | 
                android:orientation="vertical" android:layout_width="match_parent"  | 
            
| 4 | 
                - android:layout_height="match_parent">  | 
            |
| 4 | 
                + android:layout_height="match_parent"  | 
            |
| 5 | 
                + android:background="@color/background_white">  | 
            |
| 5 | 6 | 
                 | 
            
| 7 | 
                + <Button  | 
            |
| 8 | 
                + android:id="@+id/btn_login"  | 
            |
| 9 | 
                + android:layout_width="match_parent"  | 
            |
| 10 | 
                + android:layout_height="50dp"  | 
            |
| 11 | 
                + android:layout_gravity="center"  | 
            |
| 12 | 
                + android:gravity="center"  | 
            |
| 13 | 
                + android:textSize="20sp"  | 
            |
| 14 | 
                + android:textColor="@color/black"  | 
            |
| 15 | 
                + android:text="登录"/>  | 
            |
| 6 | 16 | 
                </LinearLayout>  | 
            
                @@ -0,0 +1,15 @@  | 
            ||
| 1 | 
                +<?xml version="1.0" encoding="utf-8"?>  | 
            |
| 2 | 
                +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  | 
            |
| 3 | 
                + android:orientation="vertical" android:layout_width="match_parent"  | 
            |
| 4 | 
                + android:background="@color/white"  | 
            |
| 5 | 
                + android:layout_height="match_parent">  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                + <TextView  | 
            |
| 8 | 
                + android:layout_width="match_parent"  | 
            |
| 9 | 
                + android:layout_height="wrap_content"  | 
            |
| 10 | 
                + android:textSize="40sp"  | 
            |
| 11 | 
                + android:layout_gravity="center"  | 
            |
| 12 | 
                + android:gravity="center"  | 
            |
| 13 | 
                + android:textColor="@color/black"  | 
            |
| 14 | 
                + android:text="@string/app_name"/>  | 
            |
| 15 | 
                +</LinearLayout>  | 
            
                @@ -7,6 +7,8 @@  | 
            ||
| 7 | 7 | 
                <string name="settings">设置</string>  | 
            
| 8 | 8 | 
                <string name="scene">场景</string>  | 
            
| 9 | 9 | 
                 | 
            
| 10 | 
                + <string name="network_disconnect">当前无网络连接</string>  | 
            |
| 11 | 
                +  | 
            |
| 10 | 12 | 
                <string name="qr_scan_hint">将取景框对准二维码,\n即可自动扫码</string>  | 
            
| 11 | 13 | 
                <string name="qr_scan_album">相册</string>  | 
            
| 12 | 14 | 
                <string name="scan_album_qr">选择二维码图片</string>  | 
            
                @@ -19,4 +21,10 @@  | 
            ||
| 19 | 21 | 
                <string name="check_permission_when_open_camera_error">相机打开出错,请检查是否已打开应用的相机权限</string>  | 
            
| 20 | 22 | 
                 | 
            
| 21 | 23 | 
                <string name="ok">确定</string>  | 
            
| 24 | 
                +  | 
            |
| 25 | 
                + <string name="current_version_is_latest">当前版本已是最新,无需升级</string>  | 
            |
| 26 | 
                +  | 
            |
| 27 | 
                + <string name="check_version_fail">检查更新失败,请稍后重试</string>  | 
            |
| 28 | 
                +  | 
            |
| 29 | 
                + <string name="new_version_found">发现新版本,正在更新中</string>  | 
            |
| 22 | 30 | 
                </resources>  | 
            
                @@ -1,1641 +0,0 @@  | 
            ||
| 1 | 
                -package com.android.views.swipeLayout;  | 
            |
| 2 | 
                -  | 
            |
| 3 | 
                -import android.content.Context;  | 
            |
| 4 | 
                -import android.content.res.TypedArray;  | 
            |
| 5 | 
                -import android.graphics.Rect;  | 
            |
| 6 | 
                -import android.support.annotation.Nullable;  | 
            |
| 7 | 
                -import android.support.v4.view.GravityCompat;  | 
            |
| 8 | 
                -import android.support.v4.view.ViewCompat;  | 
            |
| 9 | 
                -import android.support.v4.widget.ViewDragHelper;  | 
            |
| 10 | 
                -import android.util.AttributeSet;  | 
            |
| 11 | 
                -import android.view.GestureDetector;  | 
            |
| 12 | 
                -import android.view.Gravity;  | 
            |
| 13 | 
                -import android.view.HapticFeedbackConstants;  | 
            |
| 14 | 
                -import android.view.MotionEvent;  | 
            |
| 15 | 
                -import android.view.View;  | 
            |
| 16 | 
                -import android.view.ViewConfiguration;  | 
            |
| 17 | 
                -import android.view.ViewGroup;  | 
            |
| 18 | 
                -import android.view.ViewParent;  | 
            |
| 19 | 
                -import android.widget.AbsListView;  | 
            |
| 20 | 
                -import android.widget.AdapterView;  | 
            |
| 21 | 
                -import android.widget.FrameLayout;  | 
            |
| 22 | 
                -  | 
            |
| 23 | 
                -import com.android.views.R;  | 
            |
| 24 | 
                -  | 
            |
| 25 | 
                -import java.lang.reflect.Method;  | 
            |
| 26 | 
                -import java.util.ArrayList;  | 
            |
| 27 | 
                -import java.util.Arrays;  | 
            |
| 28 | 
                -import java.util.HashMap;  | 
            |
| 29 | 
                -import java.util.LinkedHashMap;  | 
            |
| 30 | 
                -import java.util.List;  | 
            |
| 31 | 
                -import java.util.Map;  | 
            |
| 32 | 
                -  | 
            |
| 33 | 
                -public class SwipeLayout extends FrameLayout {
               | 
            |
| 34 | 
                -  | 
            |
| 35 | 
                - private static final int DRAG_LEFT = 1;  | 
            |
| 36 | 
                - private static final int DRAG_RIGHT = 2;  | 
            |
| 37 | 
                - private static final int DRAG_TOP = 4;  | 
            |
| 38 | 
                - private static final int DRAG_BOTTOM = 8;  | 
            |
| 39 | 
                - private static final DragEdge DefaultDragEdge = DragEdge.Right;  | 
            |
| 40 | 
                -  | 
            |
| 41 | 
                - private int mTouchSlop;  | 
            |
| 42 | 
                -  | 
            |
| 43 | 
                - private DragEdge mCurrentDragEdge = DefaultDragEdge;  | 
            |
| 44 | 
                - private ViewDragHelper mDragHelper;  | 
            |
| 45 | 
                -  | 
            |
| 46 | 
                - private int mDragDistance = 0;  | 
            |
| 47 | 
                - private LinkedHashMap<DragEdge, View> mDragEdges = new LinkedHashMap<>();  | 
            |
| 48 | 
                - private ShowMode mShowMode;  | 
            |
| 49 | 
                -  | 
            |
| 50 | 
                - private float[] mEdgeSwipesOffset = new float[4];  | 
            |
| 51 | 
                -  | 
            |
| 52 | 
                - private List<SwipeListener> mSwipeListeners = new ArrayList<>();  | 
            |
| 53 | 
                - private List<SwipeDenier> mSwipeDeniers = new ArrayList<>();  | 
            |
| 54 | 
                - private Map<View, ArrayList<OnRevealListener>> mRevealListeners = new HashMap<>();  | 
            |
| 55 | 
                - private Map<View, Boolean> mShowEntirely = new HashMap<>();  | 
            |
| 56 | 
                - private Map<View, Rect> mViewBoundCache = new HashMap<>();//save all children's bound, restore in onLayout  | 
            |
| 57 | 
                -  | 
            |
| 58 | 
                - private DoubleClickListener mDoubleClickListener;  | 
            |
| 59 | 
                -  | 
            |
| 60 | 
                - private boolean mSwipeEnabled = true;  | 
            |
| 61 | 
                -    private boolean[] mSwipesEnabled = new boolean[]{true, true, true, true};
               | 
            |
| 62 | 
                - private boolean mClickToClose = false;  | 
            |
| 63 | 
                - private float mWillOpenPercentAfterOpen=0.75f;  | 
            |
| 64 | 
                - private float mWillOpenPercentAfterClose=0.25f;  | 
            |
| 65 | 
                -  | 
            |
| 66 | 
                -    public enum DragEdge {
               | 
            |
| 67 | 
                - Left,  | 
            |
| 68 | 
                - Top,  | 
            |
| 69 | 
                - Right,  | 
            |
| 70 | 
                - Bottom  | 
            |
| 71 | 
                - }  | 
            |
| 72 | 
                -  | 
            |
| 73 | 
                -    public enum ShowMode {
               | 
            |
| 74 | 
                - LayDown,  | 
            |
| 75 | 
                - PullOut  | 
            |
| 76 | 
                - }  | 
            |
| 77 | 
                -  | 
            |
| 78 | 
                -    public SwipeLayout(Context context) {
               | 
            |
| 79 | 
                - this(context, null);  | 
            |
| 80 | 
                - }  | 
            |
| 81 | 
                -  | 
            |
| 82 | 
                -    public SwipeLayout(Context context, AttributeSet attrs) {
               | 
            |
| 83 | 
                - this(context, attrs, 0);  | 
            |
| 84 | 
                - }  | 
            |
| 85 | 
                -  | 
            |
| 86 | 
                -    public SwipeLayout(Context context, AttributeSet attrs, int defStyle) {
               | 
            |
| 87 | 
                - super(context, attrs, defStyle);  | 
            |
| 88 | 
                - mDragHelper = ViewDragHelper.create(this, mDragHelperCallback);  | 
            |
| 89 | 
                - mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();  | 
            |
| 90 | 
                -  | 
            |
| 91 | 
                - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwipeLayout);  | 
            |
| 92 | 
                - int dragEdgeChoices = a.getInt(R.styleable.SwipeLayout_drag_edge, DRAG_RIGHT);  | 
            |
| 93 | 
                - mEdgeSwipesOffset[DragEdge.Left.ordinal()] = a.getDimension(R.styleable.SwipeLayout_leftEdgeSwipeOffset, 0);  | 
            |
| 94 | 
                - mEdgeSwipesOffset[DragEdge.Right.ordinal()] = a.getDimension(R.styleable.SwipeLayout_rightEdgeSwipeOffset, 0);  | 
            |
| 95 | 
                - mEdgeSwipesOffset[DragEdge.Top.ordinal()] = a.getDimension(R.styleable.SwipeLayout_topEdgeSwipeOffset, 0);  | 
            |
| 96 | 
                - mEdgeSwipesOffset[DragEdge.Bottom.ordinal()] = a.getDimension(R.styleable.SwipeLayout_bottomEdgeSwipeOffset, 0);  | 
            |
| 97 | 
                - setClickToClose(a.getBoolean(R.styleable.SwipeLayout_clickToClose, mClickToClose));  | 
            |
| 98 | 
                -  | 
            |
| 99 | 
                -        if ((dragEdgeChoices & DRAG_LEFT) == DRAG_LEFT) {
               | 
            |
| 100 | 
                - mDragEdges.put(DragEdge.Left, null);  | 
            |
| 101 | 
                - }  | 
            |
| 102 | 
                -        if ((dragEdgeChoices & DRAG_TOP) == DRAG_TOP) {
               | 
            |
| 103 | 
                - mDragEdges.put(DragEdge.Top, null);  | 
            |
| 104 | 
                - }  | 
            |
| 105 | 
                -        if ((dragEdgeChoices & DRAG_RIGHT) == DRAG_RIGHT) {
               | 
            |
| 106 | 
                - mDragEdges.put(DragEdge.Right, null);  | 
            |
| 107 | 
                - }  | 
            |
| 108 | 
                -        if ((dragEdgeChoices & DRAG_BOTTOM) == DRAG_BOTTOM) {
               | 
            |
| 109 | 
                - mDragEdges.put(DragEdge.Bottom, null);  | 
            |
| 110 | 
                - }  | 
            |
| 111 | 
                - int ordinal = a.getInt(R.styleable.SwipeLayout_show_mode, ShowMode.PullOut.ordinal());  | 
            |
| 112 | 
                - mShowMode = ShowMode.values()[ordinal];  | 
            |
| 113 | 
                - a.recycle();  | 
            |
| 114 | 
                -  | 
            |
| 115 | 
                - }  | 
            |
| 116 | 
                -  | 
            |
| 117 | 
                -    public interface SwipeListener {
               | 
            |
| 118 | 
                - void onStartOpen(SwipeLayout layout);  | 
            |
| 119 | 
                -  | 
            |
| 120 | 
                - void onOpen(SwipeLayout layout);  | 
            |
| 121 | 
                -  | 
            |
| 122 | 
                - void onStartClose(SwipeLayout layout);  | 
            |
| 123 | 
                -  | 
            |
| 124 | 
                - void onClose(SwipeLayout layout);  | 
            |
| 125 | 
                -  | 
            |
| 126 | 
                - void onUpdate(SwipeLayout layout, int leftOffset, int topOffset);  | 
            |
| 127 | 
                -  | 
            |
| 128 | 
                - void onHandRelease(SwipeLayout layout, float xvel, float yvel);  | 
            |
| 129 | 
                - }  | 
            |
| 130 | 
                -  | 
            |
| 131 | 
                -    public void addSwipeListener(SwipeListener l) {
               | 
            |
| 132 | 
                - mSwipeListeners.add(l);  | 
            |
| 133 | 
                - }  | 
            |
| 134 | 
                -  | 
            |
| 135 | 
                -    public void removeSwipeListener(SwipeListener l) {
               | 
            |
| 136 | 
                - mSwipeListeners.remove(l);  | 
            |
| 137 | 
                - }  | 
            |
| 138 | 
                -  | 
            |
| 139 | 
                -    public void removeAllSwipeListener() {
               | 
            |
| 140 | 
                - mSwipeListeners.clear();  | 
            |
| 141 | 
                - }  | 
            |
| 142 | 
                -  | 
            |
| 143 | 
                -    public interface SwipeDenier {
               | 
            |
| 144 | 
                - /*  | 
            |
| 145 | 
                - * Called in onInterceptTouchEvent Determines if this swipe event should  | 
            |
| 146 | 
                - * be denied Implement this interface if you are using views with swipe  | 
            |
| 147 | 
                - * gestures As a child of SwipeLayout  | 
            |
| 148 | 
                - *  | 
            |
| 149 | 
                - * @return true deny false allow  | 
            |
| 150 | 
                - */  | 
            |
| 151 | 
                - boolean shouldDenySwipe(MotionEvent ev);  | 
            |
| 152 | 
                - }  | 
            |
| 153 | 
                -  | 
            |
| 154 | 
                -    public void addSwipeDenier(SwipeDenier denier) {
               | 
            |
| 155 | 
                - mSwipeDeniers.add(denier);  | 
            |
| 156 | 
                - }  | 
            |
| 157 | 
                -  | 
            |
| 158 | 
                -    public void removeSwipeDenier(SwipeDenier denier) {
               | 
            |
| 159 | 
                - mSwipeDeniers.remove(denier);  | 
            |
| 160 | 
                - }  | 
            |
| 161 | 
                -  | 
            |
| 162 | 
                -    public void removeAllSwipeDeniers() {
               | 
            |
| 163 | 
                - mSwipeDeniers.clear();  | 
            |
| 164 | 
                - }  | 
            |
| 165 | 
                -  | 
            |
| 166 | 
                -    public interface OnRevealListener {
               | 
            |
| 167 | 
                - void onReveal(View child, DragEdge edge, float fraction, int distance);  | 
            |
| 168 | 
                - }  | 
            |
| 169 | 
                -  | 
            |
| 170 | 
                - /**  | 
            |
| 171 | 
                - * bind a view with a specific  | 
            |
| 172 | 
                - */  | 
            |
| 173 | 
                -    public void addRevealListener(int childId, OnRevealListener l) {
               | 
            |
| 174 | 
                - View child = findViewById(childId);  | 
            |
| 175 | 
                -        if (child == null) {
               | 
            |
| 176 | 
                -            throw new IllegalArgumentException("Child does not belong to SwipeListener.");
               | 
            |
| 177 | 
                - }  | 
            |
| 178 | 
                -  | 
            |
| 179 | 
                -        if (!mShowEntirely.containsKey(child)) {
               | 
            |
| 180 | 
                - mShowEntirely.put(child, false);  | 
            |
| 181 | 
                - }  | 
            |
| 182 | 
                - if (mRevealListeners.get(child) == null)  | 
            |
| 183 | 
                - mRevealListeners.put(child, new ArrayList<OnRevealListener>());  | 
            |
| 184 | 
                -  | 
            |
| 185 | 
                - mRevealListeners.get(child).add(l);  | 
            |
| 186 | 
                - }  | 
            |
| 187 | 
                -  | 
            |
| 188 | 
                - /**  | 
            |
| 189 | 
                - * bind multiple views with an  | 
            |
| 190 | 
                - */  | 
            |
| 191 | 
                -    public void addRevealListener(int[] childIds, OnRevealListener l) {
               | 
            |
| 192 | 
                - for (int i : childIds)  | 
            |
| 193 | 
                - addRevealListener(i, l);  | 
            |
| 194 | 
                - }  | 
            |
| 195 | 
                -  | 
            |
| 196 | 
                -    public void removeRevealListener(int childId, OnRevealListener l) {
               | 
            |
| 197 | 
                - View child = findViewById(childId);  | 
            |
| 198 | 
                -  | 
            |
| 199 | 
                - if (child == null) return;  | 
            |
| 200 | 
                -  | 
            |
| 201 | 
                - mShowEntirely.remove(child);  | 
            |
| 202 | 
                - if (mRevealListeners.containsKey(child)) mRevealListeners.get(child).remove(l);  | 
            |
| 203 | 
                - }  | 
            |
| 204 | 
                -  | 
            |
| 205 | 
                -    public void removeAllRevealListeners(int childId) {
               | 
            |
| 206 | 
                - View child = findViewById(childId);  | 
            |
| 207 | 
                -        if (child != null) {
               | 
            |
| 208 | 
                - mRevealListeners.remove(child);  | 
            |
| 209 | 
                - mShowEntirely.remove(child);  | 
            |
| 210 | 
                - }  | 
            |
| 211 | 
                - }  | 
            |
| 212 | 
                -  | 
            |
| 213 | 
                -    private ViewDragHelper.Callback mDragHelperCallback = new ViewDragHelper.Callback() {
               | 
            |
| 214 | 
                -  | 
            |
| 215 | 
                - @Override  | 
            |
| 216 | 
                -        public int clampViewPositionHorizontal(View child, int left, int dx) {
               | 
            |
| 217 | 
                -            if (child == getSurfaceView()) {
               | 
            |
| 218 | 
                -                switch (mCurrentDragEdge) {
               | 
            |
| 219 | 
                - case Top:  | 
            |
| 220 | 
                - case Bottom:  | 
            |
| 221 | 
                - return getPaddingLeft();  | 
            |
| 222 | 
                - case Left:  | 
            |
| 223 | 
                - if (left < getPaddingLeft()) return getPaddingLeft();  | 
            |
| 224 | 
                - if (left > getPaddingLeft() + mDragDistance)  | 
            |
| 225 | 
                - return getPaddingLeft() + mDragDistance;  | 
            |
| 226 | 
                - break;  | 
            |
| 227 | 
                - case Right:  | 
            |
| 228 | 
                - if (left > getPaddingLeft()) return getPaddingLeft();  | 
            |
| 229 | 
                - if (left < getPaddingLeft() - mDragDistance)  | 
            |
| 230 | 
                - return getPaddingLeft() - mDragDistance;  | 
            |
| 231 | 
                - break;  | 
            |
| 232 | 
                - }  | 
            |
| 233 | 
                -            } else if (getCurrentBottomView() == child) {
               | 
            |
| 234 | 
                -  | 
            |
| 235 | 
                -                switch (mCurrentDragEdge) {
               | 
            |
| 236 | 
                - case Top:  | 
            |
| 237 | 
                - case Bottom:  | 
            |
| 238 | 
                - return getPaddingLeft();  | 
            |
| 239 | 
                - case Left:  | 
            |
| 240 | 
                -                        if (mShowMode == ShowMode.PullOut) {
               | 
            |
| 241 | 
                - if (left > getPaddingLeft()) return getPaddingLeft();  | 
            |
| 242 | 
                - }  | 
            |
| 243 | 
                - break;  | 
            |
| 244 | 
                - case Right:  | 
            |
| 245 | 
                -                        if (mShowMode == ShowMode.PullOut) {
               | 
            |
| 246 | 
                -                            if (left < getMeasuredWidth() - mDragDistance) {
               | 
            |
| 247 | 
                - return getMeasuredWidth() - mDragDistance;  | 
            |
| 248 | 
                - }  | 
            |
| 249 | 
                - }  | 
            |
| 250 | 
                - break;  | 
            |
| 251 | 
                - }  | 
            |
| 252 | 
                - }  | 
            |
| 253 | 
                - return left;  | 
            |
| 254 | 
                - }  | 
            |
| 255 | 
                -  | 
            |
| 256 | 
                - @Override  | 
            |
| 257 | 
                -        public int clampViewPositionVertical(View child, int top, int dy) {
               | 
            |
| 258 | 
                -            if (child == getSurfaceView()) {
               | 
            |
| 259 | 
                -                switch (mCurrentDragEdge) {
               | 
            |
| 260 | 
                - case Left:  | 
            |
| 261 | 
                - case Right:  | 
            |
| 262 | 
                - return getPaddingTop();  | 
            |
| 263 | 
                - case Top:  | 
            |
| 264 | 
                - if (top < getPaddingTop()) return getPaddingTop();  | 
            |
| 265 | 
                - if (top > getPaddingTop() + mDragDistance)  | 
            |
| 266 | 
                - return getPaddingTop() + mDragDistance;  | 
            |
| 267 | 
                - break;  | 
            |
| 268 | 
                - case Bottom:  | 
            |
| 269 | 
                -                        if (top < getPaddingTop() - mDragDistance) {
               | 
            |
| 270 | 
                - return getPaddingTop() - mDragDistance;  | 
            |
| 271 | 
                - }  | 
            |
| 272 | 
                -                        if (top > getPaddingTop()) {
               | 
            |
| 273 | 
                - return getPaddingTop();  | 
            |
| 274 | 
                - }  | 
            |
| 275 | 
                - }  | 
            |
| 276 | 
                -            } else {
               | 
            |
| 277 | 
                - View surfaceView = getSurfaceView();  | 
            |
| 278 | 
                - int surfaceViewTop = surfaceView == null ? 0 : surfaceView.getTop();  | 
            |
| 279 | 
                -                switch (mCurrentDragEdge) {
               | 
            |
| 280 | 
                - case Left:  | 
            |
| 281 | 
                - case Right:  | 
            |
| 282 | 
                - return getPaddingTop();  | 
            |
| 283 | 
                - case Top:  | 
            |
| 284 | 
                -                        if (mShowMode == ShowMode.PullOut) {
               | 
            |
| 285 | 
                - if (top > getPaddingTop()) return getPaddingTop();  | 
            |
| 286 | 
                -                        } else {
               | 
            |
| 287 | 
                - if (surfaceViewTop + dy < getPaddingTop())  | 
            |
| 288 | 
                - return getPaddingTop();  | 
            |
| 289 | 
                - if (surfaceViewTop + dy > getPaddingTop() + mDragDistance)  | 
            |
| 290 | 
                - return getPaddingTop() + mDragDistance;  | 
            |
| 291 | 
                - }  | 
            |
| 292 | 
                - break;  | 
            |
| 293 | 
                - case Bottom:  | 
            |
| 294 | 
                -                        if (mShowMode == ShowMode.PullOut) {
               | 
            |
| 295 | 
                - if (top < getMeasuredHeight() - mDragDistance)  | 
            |
| 296 | 
                - return getMeasuredHeight() - mDragDistance;  | 
            |
| 297 | 
                -                        } else {
               | 
            |
| 298 | 
                - if (surfaceViewTop + dy >= getPaddingTop())  | 
            |
| 299 | 
                - return getPaddingTop();  | 
            |
| 300 | 
                - if (surfaceViewTop + dy <= getPaddingTop() - mDragDistance)  | 
            |
| 301 | 
                - return getPaddingTop() - mDragDistance;  | 
            |
| 302 | 
                - }  | 
            |
| 303 | 
                - }  | 
            |
| 304 | 
                - }  | 
            |
| 305 | 
                - return top;  | 
            |
| 306 | 
                - }  | 
            |
| 307 | 
                -  | 
            |
| 308 | 
                - @Override  | 
            |
| 309 | 
                -        public boolean tryCaptureView(View child, int pointerId) {
               | 
            |
| 310 | 
                - boolean result = child == getSurfaceView() || getBottomViews().contains(child);  | 
            |
| 311 | 
                -            if (result) {
               | 
            |
| 312 | 
                - isCloseBeforeDrag = getOpenStatus() == Status.Close;  | 
            |
| 313 | 
                - }  | 
            |
| 314 | 
                - return result;  | 
            |
| 315 | 
                - }  | 
            |
| 316 | 
                -  | 
            |
| 317 | 
                - @Override  | 
            |
| 318 | 
                -        public int getViewHorizontalDragRange(View child) {
               | 
            |
| 319 | 
                - return mDragDistance;  | 
            |
| 320 | 
                - }  | 
            |
| 321 | 
                -  | 
            |
| 322 | 
                - @Override  | 
            |
| 323 | 
                -        public int getViewVerticalDragRange(View child) {
               | 
            |
| 324 | 
                - return mDragDistance;  | 
            |
| 325 | 
                - }  | 
            |
| 326 | 
                -  | 
            |
| 327 | 
                - boolean isCloseBeforeDrag = true;  | 
            |
| 328 | 
                -  | 
            |
| 329 | 
                - @Override  | 
            |
| 330 | 
                -        public void onViewReleased(View releasedChild, float xvel, float yvel) {
               | 
            |
| 331 | 
                - super.onViewReleased(releasedChild, xvel, yvel);  | 
            |
| 332 | 
                - processHandRelease(xvel, yvel, isCloseBeforeDrag);  | 
            |
| 333 | 
                -            for (SwipeListener l : mSwipeListeners) {
               | 
            |
| 334 | 
                - l.onHandRelease(SwipeLayout.this, xvel, yvel);  | 
            |
| 335 | 
                - }  | 
            |
| 336 | 
                -  | 
            |
| 337 | 
                - invalidate();  | 
            |
| 338 | 
                - }  | 
            |
| 339 | 
                -  | 
            |
| 340 | 
                - @Override  | 
            |
| 341 | 
                -        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
               | 
            |
| 342 | 
                - View surfaceView = getSurfaceView();  | 
            |
| 343 | 
                - if (surfaceView == null) return;  | 
            |
| 344 | 
                - View currentBottomView = getCurrentBottomView();  | 
            |
| 345 | 
                - int evLeft = surfaceView.getLeft(),  | 
            |
| 346 | 
                - evRight = surfaceView.getRight(),  | 
            |
| 347 | 
                - evTop = surfaceView.getTop(),  | 
            |
| 348 | 
                - evBottom = surfaceView.getBottom();  | 
            |
| 349 | 
                -            if (changedView == surfaceView) {
               | 
            |
| 350 | 
                -  | 
            |
| 351 | 
                -                if (mShowMode == ShowMode.PullOut && currentBottomView != null) {
               | 
            |
| 352 | 
                -                    if (mCurrentDragEdge == DragEdge.Left || mCurrentDragEdge == DragEdge.Right) {
               | 
            |
| 353 | 
                - currentBottomView.offsetLeftAndRight(dx);  | 
            |
| 354 | 
                -                    } else {
               | 
            |
| 355 | 
                - currentBottomView.offsetTopAndBottom(dy);  | 
            |
| 356 | 
                - }  | 
            |
| 357 | 
                - }  | 
            |
| 358 | 
                -  | 
            |
| 359 | 
                -            } else if (getBottomViews().contains(changedView)) {
               | 
            |
| 360 | 
                -  | 
            |
| 361 | 
                -                if (mShowMode == ShowMode.PullOut) {
               | 
            |
| 362 | 
                - surfaceView.offsetLeftAndRight(dx);  | 
            |
| 363 | 
                - surfaceView.offsetTopAndBottom(dy);  | 
            |
| 364 | 
                -                } else {
               | 
            |
| 365 | 
                - Rect rect = computeBottomLayDown(mCurrentDragEdge);  | 
            |
| 366 | 
                -                    if (currentBottomView != null) {
               | 
            |
| 367 | 
                - currentBottomView.layout(rect.left, rect.top, rect.right, rect.bottom);  | 
            |
| 368 | 
                - }  | 
            |
| 369 | 
                -  | 
            |
| 370 | 
                - int newLeft = surfaceView.getLeft() + dx, newTop = surfaceView.getTop() + dy;  | 
            |
| 371 | 
                -  | 
            |
| 372 | 
                - if (mCurrentDragEdge == DragEdge.Left && newLeft < getPaddingLeft())  | 
            |
| 373 | 
                - newLeft = getPaddingLeft();  | 
            |
| 374 | 
                - else if (mCurrentDragEdge == DragEdge.Right && newLeft > getPaddingLeft())  | 
            |
| 375 | 
                - newLeft = getPaddingLeft();  | 
            |
| 376 | 
                - else if (mCurrentDragEdge == DragEdge.Top && newTop < getPaddingTop())  | 
            |
| 377 | 
                - newTop = getPaddingTop();  | 
            |
| 378 | 
                - else if (mCurrentDragEdge == DragEdge.Bottom && newTop > getPaddingTop())  | 
            |
| 379 | 
                - newTop = getPaddingTop();  | 
            |
| 380 | 
                -  | 
            |
| 381 | 
                - surfaceView.layout(newLeft, newTop, newLeft + getMeasuredWidth(), newTop + getMeasuredHeight());  | 
            |
| 382 | 
                - }  | 
            |
| 383 | 
                - }  | 
            |
| 384 | 
                -  | 
            |
| 385 | 
                - dispatchRevealEvent(evLeft, evTop, evRight, evBottom);  | 
            |
| 386 | 
                -  | 
            |
| 387 | 
                - dispatchSwipeEvent(evLeft, evTop, dx, dy);  | 
            |
| 388 | 
                -  | 
            |
| 389 | 
                - invalidate();  | 
            |
| 390 | 
                -  | 
            |
| 391 | 
                - captureChildrenBound();  | 
            |
| 392 | 
                - }  | 
            |
| 393 | 
                - };  | 
            |
| 394 | 
                -  | 
            |
| 395 | 
                - /**  | 
            |
| 396 | 
                -     * save children's bounds, so they can restore the bound in {@link #onLayout(boolean, int, int, int, int)}
               | 
            |
| 397 | 
                - */  | 
            |
| 398 | 
                -    private void captureChildrenBound(){
               | 
            |
| 399 | 
                - View currentBottomView = getCurrentBottomView();  | 
            |
| 400 | 
                -        if(getOpenStatus()== Status.Close){
               | 
            |
| 401 | 
                - mViewBoundCache.remove(currentBottomView);  | 
            |
| 402 | 
                - return;  | 
            |
| 403 | 
                - }  | 
            |
| 404 | 
                -  | 
            |
| 405 | 
                -        View[] views = new View[]{getSurfaceView(), currentBottomView};
               | 
            |
| 406 | 
                -        for (View child : views) {
               | 
            |
| 407 | 
                - Rect rect = mViewBoundCache.get(child);  | 
            |
| 408 | 
                -            if(rect==null){
               | 
            |
| 409 | 
                - rect = new Rect();  | 
            |
| 410 | 
                - mViewBoundCache.put(child, rect);  | 
            |
| 411 | 
                - }  | 
            |
| 412 | 
                - rect.left = child.getLeft();  | 
            |
| 413 | 
                - rect.top = child.getTop();  | 
            |
| 414 | 
                - rect.right = child.getRight();  | 
            |
| 415 | 
                - rect.bottom = child.getBottom();  | 
            |
| 416 | 
                - }  | 
            |
| 417 | 
                - }  | 
            |
| 418 | 
                -  | 
            |
| 419 | 
                - /**  | 
            |
| 420 | 
                - * the dispatchRevealEvent method may not always get accurate position, it  | 
            |
| 421 | 
                - * makes the view may not always get the event when the view is totally  | 
            |
| 422 | 
                - * show( fraction = 1), so , we need to calculate every time.  | 
            |
| 423 | 
                - */  | 
            |
| 424 | 
                - protected boolean isViewTotallyFirstShowed(View child, Rect relativePosition, DragEdge edge, int surfaceLeft,  | 
            |
| 425 | 
                -                                               int surfaceTop, int surfaceRight, int surfaceBottom) {
               | 
            |
| 426 | 
                - if (mShowEntirely.get(child)) return false;  | 
            |
| 427 | 
                - int childLeft = relativePosition.left;  | 
            |
| 428 | 
                - int childRight = relativePosition.right;  | 
            |
| 429 | 
                - int childTop = relativePosition.top;  | 
            |
| 430 | 
                - int childBottom = relativePosition.bottom;  | 
            |
| 431 | 
                - boolean r = false;  | 
            |
| 432 | 
                -        if (getShowMode() == ShowMode.LayDown) {
               | 
            |
| 433 | 
                - if ((edge == DragEdge.Right && surfaceRight <= childLeft)  | 
            |
| 434 | 
                - || (edge == DragEdge.Left && surfaceLeft >= childRight)  | 
            |
| 435 | 
                - || (edge == DragEdge.Top && surfaceTop >= childBottom)  | 
            |
| 436 | 
                - || (edge == DragEdge.Bottom && surfaceBottom <= childTop)) r = true;  | 
            |
| 437 | 
                -        } else if (getShowMode() == ShowMode.PullOut) {
               | 
            |
| 438 | 
                - if ((edge == DragEdge.Right && childRight <= getWidth())  | 
            |
| 439 | 
                - || (edge == DragEdge.Left && childLeft >= getPaddingLeft())  | 
            |
| 440 | 
                - || (edge == DragEdge.Top && childTop >= getPaddingTop())  | 
            |
| 441 | 
                - || (edge == DragEdge.Bottom && childBottom <= getHeight())) r = true;  | 
            |
| 442 | 
                - }  | 
            |
| 443 | 
                - return r;  | 
            |
| 444 | 
                - }  | 
            |
| 445 | 
                -  | 
            |
| 446 | 
                - protected boolean isViewShowing(View child, Rect relativePosition, DragEdge availableEdge, int surfaceLeft,  | 
            |
| 447 | 
                -                                    int surfaceTop, int surfaceRight, int surfaceBottom) {
               | 
            |
| 448 | 
                - int childLeft = relativePosition.left;  | 
            |
| 449 | 
                - int childRight = relativePosition.right;  | 
            |
| 450 | 
                - int childTop = relativePosition.top;  | 
            |
| 451 | 
                - int childBottom = relativePosition.bottom;  | 
            |
| 452 | 
                -        if (getShowMode() == ShowMode.LayDown) {
               | 
            |
| 453 | 
                -            switch (availableEdge) {
               | 
            |
| 454 | 
                - case Right:  | 
            |
| 455 | 
                -                    if (surfaceRight > childLeft && surfaceRight <= childRight) {
               | 
            |
| 456 | 
                - return true;  | 
            |
| 457 | 
                - }  | 
            |
| 458 | 
                - break;  | 
            |
| 459 | 
                - case Left:  | 
            |
| 460 | 
                -                    if (surfaceLeft < childRight && surfaceLeft >= childLeft) {
               | 
            |
| 461 | 
                - return true;  | 
            |
| 462 | 
                - }  | 
            |
| 463 | 
                - break;  | 
            |
| 464 | 
                - case Top:  | 
            |
| 465 | 
                -                    if (surfaceTop >= childTop && surfaceTop < childBottom) {
               | 
            |
| 466 | 
                - return true;  | 
            |
| 467 | 
                - }  | 
            |
| 468 | 
                - break;  | 
            |
| 469 | 
                - case Bottom:  | 
            |
| 470 | 
                -                    if (surfaceBottom > childTop && surfaceBottom <= childBottom) {
               | 
            |
| 471 | 
                - return true;  | 
            |
| 472 | 
                - }  | 
            |
| 473 | 
                - break;  | 
            |
| 474 | 
                - }  | 
            |
| 475 | 
                -        } else if (getShowMode() == ShowMode.PullOut) {
               | 
            |
| 476 | 
                -            switch (availableEdge) {
               | 
            |
| 477 | 
                - case Right:  | 
            |
| 478 | 
                - if (childLeft <= getWidth() && childRight > getWidth()) return true;  | 
            |
| 479 | 
                - break;  | 
            |
| 480 | 
                - case Left:  | 
            |
| 481 | 
                - if (childRight >= getPaddingLeft() && childLeft < getPaddingLeft()) return true;  | 
            |
| 482 | 
                - break;  | 
            |
| 483 | 
                - case Top:  | 
            |
| 484 | 
                - if (childTop < getPaddingTop() && childBottom >= getPaddingTop()) return true;  | 
            |
| 485 | 
                - break;  | 
            |
| 486 | 
                - case Bottom:  | 
            |
| 487 | 
                - if (childTop < getHeight() && childTop >= getPaddingTop()) return true;  | 
            |
| 488 | 
                - break;  | 
            |
| 489 | 
                - }  | 
            |
| 490 | 
                - }  | 
            |
| 491 | 
                - return false;  | 
            |
| 492 | 
                - }  | 
            |
| 493 | 
                -  | 
            |
| 494 | 
                -    protected Rect getRelativePosition(View child) {
               | 
            |
| 495 | 
                - View t = child;  | 
            |
| 496 | 
                - Rect r = new Rect(t.getLeft(), t.getTop(), 0, 0);  | 
            |
| 497 | 
                -        while (t.getParent() != null && t != getRootView()) {
               | 
            |
| 498 | 
                - t = (View) t.getParent();  | 
            |
| 499 | 
                - if (t == this) break;  | 
            |
| 500 | 
                - r.left += t.getLeft();  | 
            |
| 501 | 
                - r.top += t.getTop();  | 
            |
| 502 | 
                - }  | 
            |
| 503 | 
                - r.right = r.left + child.getMeasuredWidth();  | 
            |
| 504 | 
                - r.bottom = r.top + child.getMeasuredHeight();  | 
            |
| 505 | 
                - return r;  | 
            |
| 506 | 
                - }  | 
            |
| 507 | 
                -  | 
            |
| 508 | 
                - private int mEventCounter = 0;  | 
            |
| 509 | 
                -  | 
            |
| 510 | 
                -    protected void dispatchSwipeEvent(int surfaceLeft, int surfaceTop, int dx, int dy) {
               | 
            |
| 511 | 
                - DragEdge edge = getDragEdge();  | 
            |
| 512 | 
                - boolean open = true;  | 
            |
| 513 | 
                -        if (edge == DragEdge.Left) {
               | 
            |
| 514 | 
                - if (dx < 0) open = false;  | 
            |
| 515 | 
                -        } else if (edge == DragEdge.Right) {
               | 
            |
| 516 | 
                - if (dx > 0) open = false;  | 
            |
| 517 | 
                -        } else if (edge == DragEdge.Top) {
               | 
            |
| 518 | 
                - if (dy < 0) open = false;  | 
            |
| 519 | 
                -        } else if (edge == DragEdge.Bottom) {
               | 
            |
| 520 | 
                - if (dy > 0) open = false;  | 
            |
| 521 | 
                - }  | 
            |
| 522 | 
                -  | 
            |
| 523 | 
                - dispatchSwipeEvent(surfaceLeft, surfaceTop, open);  | 
            |
| 524 | 
                - }  | 
            |
| 525 | 
                -  | 
            |
| 526 | 
                -    protected void dispatchSwipeEvent(int surfaceLeft, int surfaceTop, boolean open) {
               | 
            |
| 527 | 
                - safeBottomView();  | 
            |
| 528 | 
                - Status status = getOpenStatus();  | 
            |
| 529 | 
                -  | 
            |
| 530 | 
                -        if (!mSwipeListeners.isEmpty()) {
               | 
            |
| 531 | 
                - mEventCounter++;  | 
            |
| 532 | 
                -            for (SwipeListener l : mSwipeListeners) {
               | 
            |
| 533 | 
                -                if (mEventCounter == 1) {
               | 
            |
| 534 | 
                -                    if (open) {
               | 
            |
| 535 | 
                - l.onStartOpen(this);  | 
            |
| 536 | 
                -                    } else {
               | 
            |
| 537 | 
                - l.onStartClose(this);  | 
            |
| 538 | 
                - }  | 
            |
| 539 | 
                - }  | 
            |
| 540 | 
                - l.onUpdate(SwipeLayout.this, surfaceLeft - getPaddingLeft(), surfaceTop - getPaddingTop());  | 
            |
| 541 | 
                - }  | 
            |
| 542 | 
                -  | 
            |
| 543 | 
                -            if (status == Status.Close) {
               | 
            |
| 544 | 
                -                for (SwipeListener l : mSwipeListeners) {
               | 
            |
| 545 | 
                - l.onClose(SwipeLayout.this);  | 
            |
| 546 | 
                - }  | 
            |
| 547 | 
                - mEventCounter = 0;  | 
            |
| 548 | 
                - }  | 
            |
| 549 | 
                -  | 
            |
| 550 | 
                -            if (status == Status.Open) {
               | 
            |
| 551 | 
                - View currentBottomView = getCurrentBottomView();  | 
            |
| 552 | 
                -                if (currentBottomView != null) {
               | 
            |
| 553 | 
                - currentBottomView.setEnabled(true);  | 
            |
| 554 | 
                - }  | 
            |
| 555 | 
                -                for (SwipeListener l : mSwipeListeners) {
               | 
            |
| 556 | 
                - l.onOpen(SwipeLayout.this);  | 
            |
| 557 | 
                - }  | 
            |
| 558 | 
                - mEventCounter = 0;  | 
            |
| 559 | 
                - }  | 
            |
| 560 | 
                - }  | 
            |
| 561 | 
                - }  | 
            |
| 562 | 
                -  | 
            |
| 563 | 
                - /**  | 
            |
| 564 | 
                - * prevent bottom view get any touch event. Especially in LayDown mode.  | 
            |
| 565 | 
                - */  | 
            |
| 566 | 
                -    private void safeBottomView() {
               | 
            |
| 567 | 
                - Status status = getOpenStatus();  | 
            |
| 568 | 
                - List<View> bottoms = getBottomViews();  | 
            |
| 569 | 
                -  | 
            |
| 570 | 
                -        if (status == Status.Close) {
               | 
            |
| 571 | 
                -            for (View bottom : bottoms) {
               | 
            |
| 572 | 
                -                if (bottom != null && bottom.getVisibility() != INVISIBLE) {
               | 
            |
| 573 | 
                - bottom.setVisibility(INVISIBLE);  | 
            |
| 574 | 
                - }  | 
            |
| 575 | 
                - }  | 
            |
| 576 | 
                -        } else {
               | 
            |
| 577 | 
                - View currentBottomView = getCurrentBottomView();  | 
            |
| 578 | 
                -            if (currentBottomView != null && currentBottomView.getVisibility() != VISIBLE) {
               | 
            |
| 579 | 
                - currentBottomView.setVisibility(VISIBLE);  | 
            |
| 580 | 
                - }  | 
            |
| 581 | 
                - }  | 
            |
| 582 | 
                - }  | 
            |
| 583 | 
                -  | 
            |
| 584 | 
                - protected void dispatchRevealEvent(final int surfaceLeft, final int surfaceTop, final int surfaceRight,  | 
            |
| 585 | 
                -                                       final int surfaceBottom) {
               | 
            |
| 586 | 
                - if (mRevealListeners.isEmpty()) return;  | 
            |
| 587 | 
                -        for (Map.Entry<View, ArrayList<OnRevealListener>> entry : mRevealListeners.entrySet()) {
               | 
            |
| 588 | 
                - View child = entry.getKey();  | 
            |
| 589 | 
                - Rect rect = getRelativePosition(child);  | 
            |
| 590 | 
                - if (isViewShowing(child, rect, mCurrentDragEdge, surfaceLeft, surfaceTop,  | 
            |
| 591 | 
                -                    surfaceRight, surfaceBottom)) {
               | 
            |
| 592 | 
                - mShowEntirely.put(child, false);  | 
            |
| 593 | 
                - int distance = 0;  | 
            |
| 594 | 
                - float fraction = 0f;  | 
            |
| 595 | 
                -                if (getShowMode() == ShowMode.LayDown) {
               | 
            |
| 596 | 
                -                    switch (mCurrentDragEdge) {
               | 
            |
| 597 | 
                - case Left:  | 
            |
| 598 | 
                - distance = rect.left - surfaceLeft;  | 
            |
| 599 | 
                - fraction = distance / (float) child.getWidth();  | 
            |
| 600 | 
                - break;  | 
            |
| 601 | 
                - case Right:  | 
            |
| 602 | 
                - distance = rect.right - surfaceRight;  | 
            |
| 603 | 
                - fraction = distance / (float) child.getWidth();  | 
            |
| 604 | 
                - break;  | 
            |
| 605 | 
                - case Top:  | 
            |
| 606 | 
                - distance = rect.top - surfaceTop;  | 
            |
| 607 | 
                - fraction = distance / (float) child.getHeight();  | 
            |
| 608 | 
                - break;  | 
            |
| 609 | 
                - case Bottom:  | 
            |
| 610 | 
                - distance = rect.bottom - surfaceBottom;  | 
            |
| 611 | 
                - fraction = distance / (float) child.getHeight();  | 
            |
| 612 | 
                - break;  | 
            |
| 613 | 
                - }  | 
            |
| 614 | 
                -                } else if (getShowMode() == ShowMode.PullOut) {
               | 
            |
| 615 | 
                -                    switch (mCurrentDragEdge) {
               | 
            |
| 616 | 
                - case Left:  | 
            |
| 617 | 
                - distance = rect.right - getPaddingLeft();  | 
            |
| 618 | 
                - fraction = distance / (float) child.getWidth();  | 
            |
| 619 | 
                - break;  | 
            |
| 620 | 
                - case Right:  | 
            |
| 621 | 
                - distance = rect.left - getWidth();  | 
            |
| 622 | 
                - fraction = distance / (float) child.getWidth();  | 
            |
| 623 | 
                - break;  | 
            |
| 624 | 
                - case Top:  | 
            |
| 625 | 
                - distance = rect.bottom - getPaddingTop();  | 
            |
| 626 | 
                - fraction = distance / (float) child.getHeight();  | 
            |
| 627 | 
                - break;  | 
            |
| 628 | 
                - case Bottom:  | 
            |
| 629 | 
                - distance = rect.top - getHeight();  | 
            |
| 630 | 
                - fraction = distance / (float) child.getHeight();  | 
            |
| 631 | 
                - break;  | 
            |
| 632 | 
                - }  | 
            |
| 633 | 
                - }  | 
            |
| 634 | 
                -  | 
            |
| 635 | 
                -                for (OnRevealListener l : entry.getValue()) {
               | 
            |
| 636 | 
                - l.onReveal(child, mCurrentDragEdge, Math.abs(fraction), distance);  | 
            |
| 637 | 
                -                    if (Math.abs(fraction) == 1) {
               | 
            |
| 638 | 
                - mShowEntirely.put(child, true);  | 
            |
| 639 | 
                - }  | 
            |
| 640 | 
                - }  | 
            |
| 641 | 
                - }  | 
            |
| 642 | 
                -  | 
            |
| 643 | 
                - if (isViewTotallyFirstShowed(child, rect, mCurrentDragEdge, surfaceLeft, surfaceTop,  | 
            |
| 644 | 
                -                    surfaceRight, surfaceBottom)) {
               | 
            |
| 645 | 
                - mShowEntirely.put(child, true);  | 
            |
| 646 | 
                -                for (OnRevealListener l : entry.getValue()) {
               | 
            |
| 647 | 
                - if (mCurrentDragEdge == DragEdge.Left  | 
            |
| 648 | 
                - || mCurrentDragEdge == DragEdge.Right)  | 
            |
| 649 | 
                - l.onReveal(child, mCurrentDragEdge, 1, child.getWidth());  | 
            |
| 650 | 
                - else  | 
            |
| 651 | 
                - l.onReveal(child, mCurrentDragEdge, 1, child.getHeight());  | 
            |
| 652 | 
                - }  | 
            |
| 653 | 
                - }  | 
            |
| 654 | 
                -  | 
            |
| 655 | 
                - }  | 
            |
| 656 | 
                - }  | 
            |
| 657 | 
                -  | 
            |
| 658 | 
                - @Override  | 
            |
| 659 | 
                -    public void computeScroll() {
               | 
            |
| 660 | 
                - super.computeScroll();  | 
            |
| 661 | 
                -        if (mDragHelper.continueSettling(true)) {
               | 
            |
| 662 | 
                - ViewCompat.postInvalidateOnAnimation(this);  | 
            |
| 663 | 
                - }  | 
            |
| 664 | 
                - }  | 
            |
| 665 | 
                -  | 
            |
| 666 | 
                - /**  | 
            |
| 667 | 
                -     * {@link OnLayoutChangeListener} added in API 11. I need
               | 
            |
| 668 | 
                - * to support it from API 8.  | 
            |
| 669 | 
                - */  | 
            |
| 670 | 
                -    public interface OnLayout {
               | 
            |
| 671 | 
                - void onLayout(SwipeLayout v);  | 
            |
| 672 | 
                - }  | 
            |
| 673 | 
                -  | 
            |
| 674 | 
                - private List<OnLayout> mOnLayoutListeners;  | 
            |
| 675 | 
                -  | 
            |
| 676 | 
                -    public void addOnLayoutListener(OnLayout l) {
               | 
            |
| 677 | 
                - if (mOnLayoutListeners == null) mOnLayoutListeners = new ArrayList<OnLayout>();  | 
            |
| 678 | 
                - mOnLayoutListeners.add(l);  | 
            |
| 679 | 
                - }  | 
            |
| 680 | 
                -  | 
            |
| 681 | 
                -    public void removeOnLayoutListener(OnLayout l) {
               | 
            |
| 682 | 
                - if (mOnLayoutListeners != null) mOnLayoutListeners.remove(l);  | 
            |
| 683 | 
                - }  | 
            |
| 684 | 
                -  | 
            |
| 685 | 
                -    public void clearDragEdge() {
               | 
            |
| 686 | 
                - mDragEdges.clear();  | 
            |
| 687 | 
                - }  | 
            |
| 688 | 
                -  | 
            |
| 689 | 
                -    public void setDrag(DragEdge dragEdge, int childId) {
               | 
            |
| 690 | 
                - clearDragEdge();  | 
            |
| 691 | 
                - addDrag(dragEdge, childId);  | 
            |
| 692 | 
                - }  | 
            |
| 693 | 
                -  | 
            |
| 694 | 
                -    public void setDrag(DragEdge dragEdge, View child) {
               | 
            |
| 695 | 
                - clearDragEdge();  | 
            |
| 696 | 
                - addDrag(dragEdge, child);  | 
            |
| 697 | 
                - }  | 
            |
| 698 | 
                -  | 
            |
| 699 | 
                -    public void addDrag(DragEdge dragEdge, int childId) {
               | 
            |
| 700 | 
                - addDrag(dragEdge, findViewById(childId), null);  | 
            |
| 701 | 
                - }  | 
            |
| 702 | 
                -  | 
            |
| 703 | 
                -    public void addDrag(DragEdge dragEdge, View child) {
               | 
            |
| 704 | 
                - addDrag(dragEdge, child, null);  | 
            |
| 705 | 
                - }  | 
            |
| 706 | 
                -  | 
            |
| 707 | 
                -    public void addDrag(DragEdge dragEdge, View child, ViewGroup.LayoutParams params) {
               | 
            |
| 708 | 
                - if (child == null) return;  | 
            |
| 709 | 
                -  | 
            |
| 710 | 
                -        if (params == null) {
               | 
            |
| 711 | 
                - params = generateDefaultLayoutParams();  | 
            |
| 712 | 
                - }  | 
            |
| 713 | 
                -        if (!checkLayoutParams(params)) {
               | 
            |
| 714 | 
                - params = generateLayoutParams(params);  | 
            |
| 715 | 
                - }  | 
            |
| 716 | 
                - int gravity = -1;  | 
            |
| 717 | 
                -        switch (dragEdge) {
               | 
            |
| 718 | 
                - case Left:  | 
            |
| 719 | 
                - gravity = Gravity.LEFT;  | 
            |
| 720 | 
                - break;  | 
            |
| 721 | 
                - case Right:  | 
            |
| 722 | 
                - gravity = Gravity.RIGHT;  | 
            |
| 723 | 
                - break;  | 
            |
| 724 | 
                - case Top:  | 
            |
| 725 | 
                - gravity = Gravity.TOP;  | 
            |
| 726 | 
                - break;  | 
            |
| 727 | 
                - case Bottom:  | 
            |
| 728 | 
                - gravity = Gravity.BOTTOM;  | 
            |
| 729 | 
                - break;  | 
            |
| 730 | 
                - }  | 
            |
| 731 | 
                -        if (params instanceof LayoutParams) {
               | 
            |
| 732 | 
                - ((LayoutParams) params).gravity = gravity;  | 
            |
| 733 | 
                - }  | 
            |
| 734 | 
                - addView(child, 0, params);  | 
            |
| 735 | 
                - }  | 
            |
| 736 | 
                -  | 
            |
| 737 | 
                - @Override  | 
            |
| 738 | 
                -    public void addView(View child, int index, ViewGroup.LayoutParams params) {
               | 
            |
| 739 | 
                - if (child == null) return;  | 
            |
| 740 | 
                - int gravity = Gravity.NO_GRAVITY;  | 
            |
| 741 | 
                -        try {
               | 
            |
| 742 | 
                -            gravity = (Integer) params.getClass().getField("gravity").get(params);
               | 
            |
| 743 | 
                -        } catch (Exception e) {
               | 
            |
| 744 | 
                - e.printStackTrace();  | 
            |
| 745 | 
                - }  | 
            |
| 746 | 
                -  | 
            |
| 747 | 
                -        if (gravity > 0) {
               | 
            |
| 748 | 
                - gravity = GravityCompat.getAbsoluteGravity(gravity, ViewCompat.getLayoutDirection(this));  | 
            |
| 749 | 
                -  | 
            |
| 750 | 
                -            if ((gravity & Gravity.LEFT) == Gravity.LEFT) {
               | 
            |
| 751 | 
                - mDragEdges.put(DragEdge.Left, child);  | 
            |
| 752 | 
                - }  | 
            |
| 753 | 
                -            if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {
               | 
            |
| 754 | 
                - mDragEdges.put(DragEdge.Right, child);  | 
            |
| 755 | 
                - }  | 
            |
| 756 | 
                -            if ((gravity & Gravity.TOP) == Gravity.TOP) {
               | 
            |
| 757 | 
                - mDragEdges.put(DragEdge.Top, child);  | 
            |
| 758 | 
                - }  | 
            |
| 759 | 
                -            if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
               | 
            |
| 760 | 
                - mDragEdges.put(DragEdge.Bottom, child);  | 
            |
| 761 | 
                - }  | 
            |
| 762 | 
                -        } else {
               | 
            |
| 763 | 
                -            for (Map.Entry<DragEdge, View> entry : mDragEdges.entrySet()) {
               | 
            |
| 764 | 
                -                if (entry.getValue() == null) {
               | 
            |
| 765 | 
                - //means used the drag_edge attr, the no gravity child should be use set  | 
            |
| 766 | 
                - mDragEdges.put(entry.getKey(), child);  | 
            |
| 767 | 
                - break;  | 
            |
| 768 | 
                - }  | 
            |
| 769 | 
                - }  | 
            |
| 770 | 
                - }  | 
            |
| 771 | 
                -        if (child.getParent() == this) {
               | 
            |
| 772 | 
                - return;  | 
            |
| 773 | 
                - }  | 
            |
| 774 | 
                - super.addView(child, index, params);  | 
            |
| 775 | 
                - }  | 
            |
| 776 | 
                -  | 
            |
| 777 | 
                - @Override  | 
            |
| 778 | 
                -    protected void onLayout(boolean changed, int l, int t, int r, int b) {
               | 
            |
| 779 | 
                - updateBottomViews();  | 
            |
| 780 | 
                -  | 
            |
| 781 | 
                -        if (mOnLayoutListeners != null) for (int i = 0; i < mOnLayoutListeners.size(); i++) {
               | 
            |
| 782 | 
                - mOnLayoutListeners.get(i).onLayout(this);  | 
            |
| 783 | 
                - }  | 
            |
| 784 | 
                - }  | 
            |
| 785 | 
                -  | 
            |
| 786 | 
                -    void layoutPullOut() {
               | 
            |
| 787 | 
                - View surfaceView = getSurfaceView();  | 
            |
| 788 | 
                - Rect surfaceRect = mViewBoundCache.get(surfaceView);  | 
            |
| 789 | 
                - if(surfaceRect == null) surfaceRect = computeSurfaceLayoutArea(false);  | 
            |
| 790 | 
                -        if (surfaceView != null) {
               | 
            |
| 791 | 
                - surfaceView.layout(surfaceRect.left, surfaceRect.top, surfaceRect.right, surfaceRect.bottom);  | 
            |
| 792 | 
                - bringChildToFront(surfaceView);  | 
            |
| 793 | 
                - }  | 
            |
| 794 | 
                - View currentBottomView = getCurrentBottomView();  | 
            |
| 795 | 
                - Rect bottomViewRect = mViewBoundCache.get(currentBottomView);  | 
            |
| 796 | 
                - if(bottomViewRect == null) bottomViewRect = computeBottomLayoutAreaViaSurface(ShowMode.PullOut, surfaceRect);  | 
            |
| 797 | 
                -        if (currentBottomView != null) {
               | 
            |
| 798 | 
                - currentBottomView.layout(bottomViewRect.left, bottomViewRect.top, bottomViewRect.right, bottomViewRect.bottom);  | 
            |
| 799 | 
                - }  | 
            |
| 800 | 
                - }  | 
            |
| 801 | 
                -  | 
            |
| 802 | 
                -    void layoutLayDown() {
               | 
            |
| 803 | 
                - View surfaceView = getSurfaceView();  | 
            |
| 804 | 
                - Rect surfaceRect = mViewBoundCache.get(surfaceView);  | 
            |
| 805 | 
                - if(surfaceRect == null) surfaceRect = computeSurfaceLayoutArea(false);  | 
            |
| 806 | 
                -        if (surfaceView != null) {
               | 
            |
| 807 | 
                - surfaceView.layout(surfaceRect.left, surfaceRect.top, surfaceRect.right, surfaceRect.bottom);  | 
            |
| 808 | 
                - bringChildToFront(surfaceView);  | 
            |
| 809 | 
                - }  | 
            |
| 810 | 
                - View currentBottomView = getCurrentBottomView();  | 
            |
| 811 | 
                - Rect bottomViewRect = mViewBoundCache.get(currentBottomView);  | 
            |
| 812 | 
                - if(bottomViewRect == null) bottomViewRect = computeBottomLayoutAreaViaSurface(ShowMode.LayDown, surfaceRect);  | 
            |
| 813 | 
                -        if (currentBottomView != null) {
               | 
            |
| 814 | 
                - currentBottomView.layout(bottomViewRect.left, bottomViewRect.top, bottomViewRect.right, bottomViewRect.bottom);  | 
            |
| 815 | 
                - }  | 
            |
| 816 | 
                - }  | 
            |
| 817 | 
                -  | 
            |
| 818 | 
                - private boolean mIsBeingDragged;  | 
            |
| 819 | 
                -  | 
            |
| 820 | 
                -    private void checkCanDrag(MotionEvent ev) {
               | 
            |
| 821 | 
                - if (mIsBeingDragged) return;  | 
            |
| 822 | 
                -        if (getOpenStatus() == Status.Middle) {
               | 
            |
| 823 | 
                - mIsBeingDragged = true;  | 
            |
| 824 | 
                - return;  | 
            |
| 825 | 
                - }  | 
            |
| 826 | 
                - Status status = getOpenStatus();  | 
            |
| 827 | 
                - float distanceX = ev.getRawX() - sX;  | 
            |
| 828 | 
                - float distanceY = ev.getRawY() - sY;  | 
            |
| 829 | 
                - float angle = Math.abs(distanceY / distanceX);  | 
            |
| 830 | 
                - angle = (float) Math.toDegrees(Math.atan(angle));  | 
            |
| 831 | 
                -        if (getOpenStatus() == Status.Close) {
               | 
            |
| 832 | 
                - DragEdge dragEdge;  | 
            |
| 833 | 
                -            if (angle < 45) {
               | 
            |
| 834 | 
                -                if (distanceX > 0 && isLeftSwipeEnabled()) {
               | 
            |
| 835 | 
                - dragEdge = DragEdge.Left;  | 
            |
| 836 | 
                -                } else if (distanceX < 0 && isRightSwipeEnabled()) {
               | 
            |
| 837 | 
                - dragEdge = DragEdge.Right;  | 
            |
| 838 | 
                - } else return;  | 
            |
| 839 | 
                -  | 
            |
| 840 | 
                -            } else {
               | 
            |
| 841 | 
                -                if (distanceY > 0 && isTopSwipeEnabled()) {
               | 
            |
| 842 | 
                - dragEdge = DragEdge.Top;  | 
            |
| 843 | 
                -                } else if (distanceY < 0 && isBottomSwipeEnabled()) {
               | 
            |
| 844 | 
                - dragEdge = DragEdge.Bottom;  | 
            |
| 845 | 
                - } else return;  | 
            |
| 846 | 
                - }  | 
            |
| 847 | 
                - setCurrentDragEdge(dragEdge);  | 
            |
| 848 | 
                - }  | 
            |
| 849 | 
                -  | 
            |
| 850 | 
                - boolean doNothing = false;  | 
            |
| 851 | 
                -        if (mCurrentDragEdge == DragEdge.Right) {
               | 
            |
| 852 | 
                - boolean suitable = (status == Status.Open && distanceX > mTouchSlop)  | 
            |
| 853 | 
                - || (status == Status.Close && distanceX < -mTouchSlop);  | 
            |
| 854 | 
                - suitable = suitable || (status == Status.Middle);  | 
            |
| 855 | 
                -  | 
            |
| 856 | 
                -            if (angle > 30 || !suitable) {
               | 
            |
| 857 | 
                - doNothing = true;  | 
            |
| 858 | 
                - }  | 
            |
| 859 | 
                - }  | 
            |
| 860 | 
                -  | 
            |
| 861 | 
                -        if (mCurrentDragEdge == DragEdge.Left) {
               | 
            |
| 862 | 
                - boolean suitable = (status == Status.Open && distanceX < -mTouchSlop)  | 
            |
| 863 | 
                - || (status == Status.Close && distanceX > mTouchSlop);  | 
            |
| 864 | 
                - suitable = suitable || status == Status.Middle;  | 
            |
| 865 | 
                -  | 
            |
| 866 | 
                -            if (angle > 30 || !suitable) {
               | 
            |
| 867 | 
                - doNothing = true;  | 
            |
| 868 | 
                - }  | 
            |
| 869 | 
                - }  | 
            |
| 870 | 
                -  | 
            |
| 871 | 
                -        if (mCurrentDragEdge == DragEdge.Top) {
               | 
            |
| 872 | 
                - boolean suitable = (status == Status.Open && distanceY < -mTouchSlop)  | 
            |
| 873 | 
                - || (status == Status.Close && distanceY > mTouchSlop);  | 
            |
| 874 | 
                - suitable = suitable || status == Status.Middle;  | 
            |
| 875 | 
                -  | 
            |
| 876 | 
                -            if (angle < 60 || !suitable) {
               | 
            |
| 877 | 
                - doNothing = true;  | 
            |
| 878 | 
                - }  | 
            |
| 879 | 
                - }  | 
            |
| 880 | 
                -  | 
            |
| 881 | 
                -        if (mCurrentDragEdge == DragEdge.Bottom) {
               | 
            |
| 882 | 
                - boolean suitable = (status == Status.Open && distanceY > mTouchSlop)  | 
            |
| 883 | 
                - || (status == Status.Close && distanceY < -mTouchSlop);  | 
            |
| 884 | 
                - suitable = suitable || status == Status.Middle;  | 
            |
| 885 | 
                -  | 
            |
| 886 | 
                -            if (angle < 60 || !suitable) {
               | 
            |
| 887 | 
                - doNothing = true;  | 
            |
| 888 | 
                - }  | 
            |
| 889 | 
                - }  | 
            |
| 890 | 
                - mIsBeingDragged = !doNothing;  | 
            |
| 891 | 
                - }  | 
            |
| 892 | 
                -  | 
            |
| 893 | 
                - @Override  | 
            |
| 894 | 
                -    public boolean onInterceptTouchEvent(MotionEvent ev) {
               | 
            |
| 895 | 
                -        if (!isSwipeEnabled()) {
               | 
            |
| 896 | 
                - return false;  | 
            |
| 897 | 
                - }  | 
            |
| 898 | 
                -        if (mClickToClose && getOpenStatus() == Status.Open && isTouchOnSurface(ev)) {
               | 
            |
| 899 | 
                - return true;  | 
            |
| 900 | 
                - }  | 
            |
| 901 | 
                -        for (SwipeDenier denier : mSwipeDeniers) {
               | 
            |
| 902 | 
                -            if (denier != null && denier.shouldDenySwipe(ev)) {
               | 
            |
| 903 | 
                - return false;  | 
            |
| 904 | 
                - }  | 
            |
| 905 | 
                - }  | 
            |
| 906 | 
                -  | 
            |
| 907 | 
                -        switch (ev.getAction()) {
               | 
            |
| 908 | 
                - case MotionEvent.ACTION_DOWN:  | 
            |
| 909 | 
                - mDragHelper.processTouchEvent(ev);  | 
            |
| 910 | 
                - mIsBeingDragged = false;  | 
            |
| 911 | 
                - sX = ev.getRawX();  | 
            |
| 912 | 
                - sY = ev.getRawY();  | 
            |
| 913 | 
                - //if the swipe is in middle state(scrolling), should intercept the touch  | 
            |
| 914 | 
                -                if (getOpenStatus() == Status.Middle) {
               | 
            |
| 915 | 
                - mIsBeingDragged = true;  | 
            |
| 916 | 
                - }  | 
            |
| 917 | 
                - break;  | 
            |
| 918 | 
                - case MotionEvent.ACTION_MOVE:  | 
            |
| 919 | 
                - boolean beforeCheck = mIsBeingDragged;  | 
            |
| 920 | 
                - checkCanDrag(ev);  | 
            |
| 921 | 
                -                if (mIsBeingDragged) {
               | 
            |
| 922 | 
                - ViewParent parent = getParent();  | 
            |
| 923 | 
                -                    if (parent != null) {
               | 
            |
| 924 | 
                - parent.requestDisallowInterceptTouchEvent(true);  | 
            |
| 925 | 
                - }  | 
            |
| 926 | 
                - }  | 
            |
| 927 | 
                -                if (!beforeCheck && mIsBeingDragged) {
               | 
            |
| 928 | 
                - //let children has one chance to catch the touch, and request the swipe not intercept  | 
            |
| 929 | 
                - //useful when swipeLayout wrap a swipeLayout or other gestural layout  | 
            |
| 930 | 
                - return false;  | 
            |
| 931 | 
                - }  | 
            |
| 932 | 
                - break;  | 
            |
| 933 | 
                -  | 
            |
| 934 | 
                - case MotionEvent.ACTION_CANCEL:  | 
            |
| 935 | 
                - case MotionEvent.ACTION_UP:  | 
            |
| 936 | 
                - mIsBeingDragged = false;  | 
            |
| 937 | 
                - mDragHelper.processTouchEvent(ev);  | 
            |
| 938 | 
                - break;  | 
            |
| 939 | 
                - default://handle other action, such as ACTION_POINTER_DOWN/UP  | 
            |
| 940 | 
                - mDragHelper.processTouchEvent(ev);  | 
            |
| 941 | 
                - }  | 
            |
| 942 | 
                - return mIsBeingDragged;  | 
            |
| 943 | 
                - }  | 
            |
| 944 | 
                -  | 
            |
| 945 | 
                - private float sX = -1, sY = -1;  | 
            |
| 946 | 
                -  | 
            |
| 947 | 
                - @Override  | 
            |
| 948 | 
                -    public boolean onTouchEvent(MotionEvent event) {
               | 
            |
| 949 | 
                - if (!isSwipeEnabled()) return super.onTouchEvent(event);  | 
            |
| 950 | 
                -  | 
            |
| 951 | 
                - int action = event.getActionMasked();  | 
            |
| 952 | 
                - gestureDetector.onTouchEvent(event);  | 
            |
| 953 | 
                -  | 
            |
| 954 | 
                -        switch (action) {
               | 
            |
| 955 | 
                - case MotionEvent.ACTION_DOWN:  | 
            |
| 956 | 
                - mDragHelper.processTouchEvent(event);  | 
            |
| 957 | 
                - sX = event.getRawX();  | 
            |
| 958 | 
                - sY = event.getRawY();  | 
            |
| 959 | 
                -  | 
            |
| 960 | 
                -  | 
            |
| 961 | 
                -            case MotionEvent.ACTION_MOVE: {
               | 
            |
| 962 | 
                - //the drag state and the direction are already judged at onInterceptTouchEvent  | 
            |
| 963 | 
                - checkCanDrag(event);  | 
            |
| 964 | 
                -                if (mIsBeingDragged) {
               | 
            |
| 965 | 
                - getParent().requestDisallowInterceptTouchEvent(true);  | 
            |
| 966 | 
                - mDragHelper.processTouchEvent(event);  | 
            |
| 967 | 
                - }  | 
            |
| 968 | 
                - break;  | 
            |
| 969 | 
                - }  | 
            |
| 970 | 
                - case MotionEvent.ACTION_UP:  | 
            |
| 971 | 
                - case MotionEvent.ACTION_CANCEL:  | 
            |
| 972 | 
                - mIsBeingDragged = false;  | 
            |
| 973 | 
                - mDragHelper.processTouchEvent(event);  | 
            |
| 974 | 
                - break;  | 
            |
| 975 | 
                -  | 
            |
| 976 | 
                - default://handle other action, such as ACTION_POINTER_DOWN/UP  | 
            |
| 977 | 
                - mDragHelper.processTouchEvent(event);  | 
            |
| 978 | 
                - }  | 
            |
| 979 | 
                -  | 
            |
| 980 | 
                - return super.onTouchEvent(event) || mIsBeingDragged || action == MotionEvent.ACTION_DOWN;  | 
            |
| 981 | 
                - }  | 
            |
| 982 | 
                -  | 
            |
| 983 | 
                -    public boolean isClickToClose() {
               | 
            |
| 984 | 
                - return mClickToClose;  | 
            |
| 985 | 
                - }  | 
            |
| 986 | 
                -  | 
            |
| 987 | 
                -    public void setClickToClose(boolean mClickToClose) {
               | 
            |
| 988 | 
                - this.mClickToClose = mClickToClose;  | 
            |
| 989 | 
                - }  | 
            |
| 990 | 
                -  | 
            |
| 991 | 
                -    public void setSwipeEnabled(boolean enabled) {
               | 
            |
| 992 | 
                - mSwipeEnabled = enabled;  | 
            |
| 993 | 
                - }  | 
            |
| 994 | 
                -  | 
            |
| 995 | 
                -    public boolean isSwipeEnabled() {
               | 
            |
| 996 | 
                - return mSwipeEnabled;  | 
            |
| 997 | 
                - }  | 
            |
| 998 | 
                -  | 
            |
| 999 | 
                -    public boolean isLeftSwipeEnabled() {
               | 
            |
| 1000 | 
                - View bottomView = mDragEdges.get(DragEdge.Left);  | 
            |
| 1001 | 
                - return bottomView != null && bottomView.getParent() == this  | 
            |
| 1002 | 
                - && bottomView != getSurfaceView() && mSwipesEnabled[DragEdge.Left.ordinal()];  | 
            |
| 1003 | 
                - }  | 
            |
| 1004 | 
                -  | 
            |
| 1005 | 
                -    public void setLeftSwipeEnabled(boolean leftSwipeEnabled) {
               | 
            |
| 1006 | 
                - this.mSwipesEnabled[DragEdge.Left.ordinal()] = leftSwipeEnabled;  | 
            |
| 1007 | 
                - }  | 
            |
| 1008 | 
                -  | 
            |
| 1009 | 
                -    public boolean isRightSwipeEnabled() {
               | 
            |
| 1010 | 
                - View bottomView = mDragEdges.get(DragEdge.Right);  | 
            |
| 1011 | 
                - return bottomView != null && bottomView.getParent() == this  | 
            |
| 1012 | 
                - && bottomView != getSurfaceView() && mSwipesEnabled[DragEdge.Right.ordinal()];  | 
            |
| 1013 | 
                - }  | 
            |
| 1014 | 
                -  | 
            |
| 1015 | 
                -    public void setRightSwipeEnabled(boolean rightSwipeEnabled) {
               | 
            |
| 1016 | 
                - this.mSwipesEnabled[DragEdge.Right.ordinal()] = rightSwipeEnabled;  | 
            |
| 1017 | 
                - }  | 
            |
| 1018 | 
                -  | 
            |
| 1019 | 
                -    public boolean isTopSwipeEnabled() {
               | 
            |
| 1020 | 
                - View bottomView = mDragEdges.get(DragEdge.Top);  | 
            |
| 1021 | 
                - return bottomView != null && bottomView.getParent() == this  | 
            |
| 1022 | 
                - && bottomView != getSurfaceView() && mSwipesEnabled[DragEdge.Top.ordinal()];  | 
            |
| 1023 | 
                - }  | 
            |
| 1024 | 
                -  | 
            |
| 1025 | 
                -    public void setTopSwipeEnabled(boolean topSwipeEnabled) {
               | 
            |
| 1026 | 
                - this.mSwipesEnabled[DragEdge.Top.ordinal()] = topSwipeEnabled;  | 
            |
| 1027 | 
                - }  | 
            |
| 1028 | 
                -  | 
            |
| 1029 | 
                -    public boolean isBottomSwipeEnabled() {
               | 
            |
| 1030 | 
                - View bottomView = mDragEdges.get(DragEdge.Bottom);  | 
            |
| 1031 | 
                - return bottomView != null && bottomView.getParent() == this  | 
            |
| 1032 | 
                - && bottomView != getSurfaceView() && mSwipesEnabled[DragEdge.Bottom.ordinal()];  | 
            |
| 1033 | 
                - }  | 
            |
| 1034 | 
                -  | 
            |
| 1035 | 
                -    public void setBottomSwipeEnabled(boolean bottomSwipeEnabled) {
               | 
            |
| 1036 | 
                - this.mSwipesEnabled[DragEdge.Bottom.ordinal()] = bottomSwipeEnabled;  | 
            |
| 1037 | 
                - }  | 
            |
| 1038 | 
                - /***  | 
            |
| 1039 | 
                - * Returns the percentage of revealing at which the view below should the view finish opening  | 
            |
| 1040 | 
                - * if it was already open before dragging  | 
            |
| 1041 | 
                - * @returns The percentage of view revealed to trigger, default value is 0.25  | 
            |
| 1042 | 
                - */  | 
            |
| 1043 | 
                -    public float getWillOpenPercentAfterOpen() {
               | 
            |
| 1044 | 
                - return mWillOpenPercentAfterOpen;  | 
            |
| 1045 | 
                - }  | 
            |
| 1046 | 
                -  | 
            |
| 1047 | 
                - /***  | 
            |
| 1048 | 
                - * Allows to stablish at what percentage of revealing the view below should the view finish opening  | 
            |
| 1049 | 
                - * if it was already open before dragging  | 
            |
| 1050 | 
                - * @param willOpenPercentAfterOpen The percentage of view revealed to trigger, default value is 0.25  | 
            |
| 1051 | 
                - */  | 
            |
| 1052 | 
                -    public void setWillOpenPercentAfterOpen(float willOpenPercentAfterOpen) {
               | 
            |
| 1053 | 
                - this.mWillOpenPercentAfterOpen = willOpenPercentAfterOpen;  | 
            |
| 1054 | 
                - }  | 
            |
| 1055 | 
                - /***  | 
            |
| 1056 | 
                - * Returns the percentage of revealing at which the view below should the view finish opening  | 
            |
| 1057 | 
                - * if it was already closed before dragging  | 
            |
| 1058 | 
                - * @returns The percentage of view revealed to trigger, default value is 0.25  | 
            |
| 1059 | 
                - */  | 
            |
| 1060 | 
                -    public float getWillOpenPercentAfterClose() {
               | 
            |
| 1061 | 
                - return mWillOpenPercentAfterClose;  | 
            |
| 1062 | 
                - }  | 
            |
| 1063 | 
                - /***  | 
            |
| 1064 | 
                - * Allows to stablish at what percentage of revealing the view below should the view finish opening  | 
            |
| 1065 | 
                - * if it was already closed before dragging  | 
            |
| 1066 | 
                - * @param willOpenPercentAfterClose The percentage of view revealed to trigger, default value is 0.75  | 
            |
| 1067 | 
                - */  | 
            |
| 1068 | 
                -    public void setWillOpenPercentAfterClose(float willOpenPercentAfterClose) {
               | 
            |
| 1069 | 
                - this.mWillOpenPercentAfterClose = willOpenPercentAfterClose;  | 
            |
| 1070 | 
                - }  | 
            |
| 1071 | 
                -  | 
            |
| 1072 | 
                -    private boolean insideAdapterView() {
               | 
            |
| 1073 | 
                - return getAdapterView() != null;  | 
            |
| 1074 | 
                - }  | 
            |
| 1075 | 
                -  | 
            |
| 1076 | 
                -    private AdapterView getAdapterView() {
               | 
            |
| 1077 | 
                - ViewParent t = getParent();  | 
            |
| 1078 | 
                -        if (t instanceof AdapterView) {
               | 
            |
| 1079 | 
                - return (AdapterView) t;  | 
            |
| 1080 | 
                - }  | 
            |
| 1081 | 
                - return null;  | 
            |
| 1082 | 
                - }  | 
            |
| 1083 | 
                -  | 
            |
| 1084 | 
                -    private void performAdapterViewItemClick() {
               | 
            |
| 1085 | 
                - if (getOpenStatus() != Status.Close) return;  | 
            |
| 1086 | 
                - ViewParent t = getParent();  | 
            |
| 1087 | 
                -        if (t instanceof AdapterView) {
               | 
            |
| 1088 | 
                - AdapterView view = (AdapterView) t;  | 
            |
| 1089 | 
                - int p = view.getPositionForView(SwipeLayout.this);  | 
            |
| 1090 | 
                -            if (p != AdapterView.INVALID_POSITION) {
               | 
            |
| 1091 | 
                - view.performItemClick(view.getChildAt(p - view.getFirstVisiblePosition()), p, view  | 
            |
| 1092 | 
                - .getAdapter().getItemId(p));  | 
            |
| 1093 | 
                - }  | 
            |
| 1094 | 
                - }  | 
            |
| 1095 | 
                - }  | 
            |
| 1096 | 
                -  | 
            |
| 1097 | 
                -    private boolean performAdapterViewItemLongClick() {
               | 
            |
| 1098 | 
                - if (getOpenStatus() != Status.Close) return false;  | 
            |
| 1099 | 
                - ViewParent t = getParent();  | 
            |
| 1100 | 
                -        if (t instanceof AdapterView) {
               | 
            |
| 1101 | 
                - AdapterView view = (AdapterView) t;  | 
            |
| 1102 | 
                - int p = view.getPositionForView(SwipeLayout.this);  | 
            |
| 1103 | 
                - if (p == AdapterView.INVALID_POSITION) return false;  | 
            |
| 1104 | 
                - long vId = view.getItemIdAtPosition(p);  | 
            |
| 1105 | 
                - boolean handled = false;  | 
            |
| 1106 | 
                -            try {
               | 
            |
| 1107 | 
                -                Method m = AbsListView.class.getDeclaredMethod("performLongPress", View.class, int.class, long.class);
               | 
            |
| 1108 | 
                - m.setAccessible(true);  | 
            |
| 1109 | 
                - handled = (boolean) m.invoke(view, SwipeLayout.this, p, vId);  | 
            |
| 1110 | 
                -  | 
            |
| 1111 | 
                -            } catch (Exception e) {
               | 
            |
| 1112 | 
                - e.printStackTrace();  | 
            |
| 1113 | 
                -  | 
            |
| 1114 | 
                -                if (view.getOnItemLongClickListener() != null) {
               | 
            |
| 1115 | 
                - handled = view.getOnItemLongClickListener().onItemLongClick(view, SwipeLayout.this, p, vId);  | 
            |
| 1116 | 
                - }  | 
            |
| 1117 | 
                -                if (handled) {
               | 
            |
| 1118 | 
                - view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);  | 
            |
| 1119 | 
                - }  | 
            |
| 1120 | 
                - }  | 
            |
| 1121 | 
                - return handled;  | 
            |
| 1122 | 
                - }  | 
            |
| 1123 | 
                - return false;  | 
            |
| 1124 | 
                - }  | 
            |
| 1125 | 
                -  | 
            |
| 1126 | 
                - @Override  | 
            |
| 1127 | 
                -    protected void onAttachedToWindow() {
               | 
            |
| 1128 | 
                - super.onAttachedToWindow();  | 
            |
| 1129 | 
                -        if (insideAdapterView()) {
               | 
            |
| 1130 | 
                -            if (clickListener == null) {
               | 
            |
| 1131 | 
                -                setOnClickListener(new OnClickListener() {
               | 
            |
| 1132 | 
                - @Override  | 
            |
| 1133 | 
                -                    public void onClick(View v) {
               | 
            |
| 1134 | 
                - performAdapterViewItemClick();  | 
            |
| 1135 | 
                - }  | 
            |
| 1136 | 
                - });  | 
            |
| 1137 | 
                - }  | 
            |
| 1138 | 
                -            if (longClickListener == null) {
               | 
            |
| 1139 | 
                -                setOnLongClickListener(new OnLongClickListener() {
               | 
            |
| 1140 | 
                - @Override  | 
            |
| 1141 | 
                -                    public boolean onLongClick(View v) {
               | 
            |
| 1142 | 
                - performAdapterViewItemLongClick();  | 
            |
| 1143 | 
                - return true;  | 
            |
| 1144 | 
                - }  | 
            |
| 1145 | 
                - });  | 
            |
| 1146 | 
                - }  | 
            |
| 1147 | 
                - }  | 
            |
| 1148 | 
                - }  | 
            |
| 1149 | 
                -  | 
            |
| 1150 | 
                - OnClickListener clickListener;  | 
            |
| 1151 | 
                -  | 
            |
| 1152 | 
                - @Override  | 
            |
| 1153 | 
                -    public void setOnClickListener(OnClickListener l) {
               | 
            |
| 1154 | 
                - super.setOnClickListener(l);  | 
            |
| 1155 | 
                - clickListener = l;  | 
            |
| 1156 | 
                - }  | 
            |
| 1157 | 
                -  | 
            |
| 1158 | 
                - OnLongClickListener longClickListener;  | 
            |
| 1159 | 
                -  | 
            |
| 1160 | 
                - @Override  | 
            |
| 1161 | 
                -    public void setOnLongClickListener(OnLongClickListener l) {
               | 
            |
| 1162 | 
                - super.setOnLongClickListener(l);  | 
            |
| 1163 | 
                - longClickListener = l;  | 
            |
| 1164 | 
                - }  | 
            |
| 1165 | 
                -  | 
            |
| 1166 | 
                - private Rect hitSurfaceRect;  | 
            |
| 1167 | 
                -  | 
            |
| 1168 | 
                -    private boolean isTouchOnSurface(MotionEvent ev) {
               | 
            |
| 1169 | 
                - View surfaceView = getSurfaceView();  | 
            |
| 1170 | 
                -        if (surfaceView == null) {
               | 
            |
| 1171 | 
                - return false;  | 
            |
| 1172 | 
                - }  | 
            |
| 1173 | 
                -        if (hitSurfaceRect == null) {
               | 
            |
| 1174 | 
                - hitSurfaceRect = new Rect();  | 
            |
| 1175 | 
                - }  | 
            |
| 1176 | 
                - surfaceView.getHitRect(hitSurfaceRect);  | 
            |
| 1177 | 
                - return hitSurfaceRect.contains((int) ev.getX(), (int) ev.getY());  | 
            |
| 1178 | 
                - }  | 
            |
| 1179 | 
                -  | 
            |
| 1180 | 
                - private GestureDetector gestureDetector = new GestureDetector(getContext(), new SwipeDetector());  | 
            |
| 1181 | 
                -  | 
            |
| 1182 | 
                -    class SwipeDetector extends GestureDetector.SimpleOnGestureListener {
               | 
            |
| 1183 | 
                - @Override  | 
            |
| 1184 | 
                -        public boolean onSingleTapUp(MotionEvent e) {
               | 
            |
| 1185 | 
                -            if (mClickToClose && isTouchOnSurface(e)) {
               | 
            |
| 1186 | 
                - close();  | 
            |
| 1187 | 
                - }  | 
            |
| 1188 | 
                - return super.onSingleTapUp(e);  | 
            |
| 1189 | 
                - }  | 
            |
| 1190 | 
                -  | 
            |
| 1191 | 
                - @Override  | 
            |
| 1192 | 
                -        public boolean onDoubleTap(MotionEvent e) {
               | 
            |
| 1193 | 
                -            if (mDoubleClickListener != null) {
               | 
            |
| 1194 | 
                - View target;  | 
            |
| 1195 | 
                - View bottom = getCurrentBottomView();  | 
            |
| 1196 | 
                - View surface = getSurfaceView();  | 
            |
| 1197 | 
                - if (bottom != null && e.getX() > bottom.getLeft() && e.getX() < bottom.getRight()  | 
            |
| 1198 | 
                -                        && e.getY() > bottom.getTop() && e.getY() < bottom.getBottom()) {
               | 
            |
| 1199 | 
                - target = bottom;  | 
            |
| 1200 | 
                -                } else {
               | 
            |
| 1201 | 
                - target = surface;  | 
            |
| 1202 | 
                - }  | 
            |
| 1203 | 
                - mDoubleClickListener.onDoubleClick(SwipeLayout.this, target == surface);  | 
            |
| 1204 | 
                - }  | 
            |
| 1205 | 
                - return true;  | 
            |
| 1206 | 
                - }  | 
            |
| 1207 | 
                - }  | 
            |
| 1208 | 
                -  | 
            |
| 1209 | 
                - /**  | 
            |
| 1210 | 
                - * set the drag distance, it will force set the bottom view's width or  | 
            |
| 1211 | 
                - * height via this value.  | 
            |
| 1212 | 
                - *  | 
            |
| 1213 | 
                - * @param max max distance in dp unit  | 
            |
| 1214 | 
                - */  | 
            |
| 1215 | 
                -    public void setDragDistance(int max) {
               | 
            |
| 1216 | 
                - if (max < 0) max = 0;  | 
            |
| 1217 | 
                - mDragDistance = dp2px(max);  | 
            |
| 1218 | 
                - requestLayout();  | 
            |
| 1219 | 
                - }  | 
            |
| 1220 | 
                -  | 
            |
| 1221 | 
                - /**  | 
            |
| 1222 | 
                - * There are 2 diffirent show mode.  | 
            |
| 1223 | 
                - *  | 
            |
| 1224 | 
                - * @param mode  | 
            |
| 1225 | 
                - */  | 
            |
| 1226 | 
                -    public void setShowMode(ShowMode mode) {
               | 
            |
| 1227 | 
                - mShowMode = mode;  | 
            |
| 1228 | 
                - requestLayout();  | 
            |
| 1229 | 
                - }  | 
            |
| 1230 | 
                -  | 
            |
| 1231 | 
                -    public DragEdge getDragEdge() {
               | 
            |
| 1232 | 
                - return mCurrentDragEdge;  | 
            |
| 1233 | 
                - }  | 
            |
| 1234 | 
                -  | 
            |
| 1235 | 
                -    public int getDragDistance() {
               | 
            |
| 1236 | 
                - return mDragDistance;  | 
            |
| 1237 | 
                - }  | 
            |
| 1238 | 
                -  | 
            |
| 1239 | 
                -    public ShowMode getShowMode() {
               | 
            |
| 1240 | 
                - return mShowMode;  | 
            |
| 1241 | 
                - }  | 
            |
| 1242 | 
                -  | 
            |
| 1243 | 
                - /**  | 
            |
| 1244 | 
                - * return null if there is no surface view(no children)  | 
            |
| 1245 | 
                - */  | 
            |
| 1246 | 
                -    public View getSurfaceView() {
               | 
            |
| 1247 | 
                - if (getChildCount() == 0) return null;  | 
            |
| 1248 | 
                - return getChildAt(getChildCount() - 1);  | 
            |
| 1249 | 
                - }  | 
            |
| 1250 | 
                -  | 
            |
| 1251 | 
                - /**  | 
            |
| 1252 | 
                - * return null if there is no bottom view  | 
            |
| 1253 | 
                - */  | 
            |
| 1254 | 
                - @Nullable  | 
            |
| 1255 | 
                -    public View getCurrentBottomView() {
               | 
            |
| 1256 | 
                - List<View> bottoms = getBottomViews();  | 
            |
| 1257 | 
                -        if (mCurrentDragEdge.ordinal() < bottoms.size()) {
               | 
            |
| 1258 | 
                - return bottoms.get(mCurrentDragEdge.ordinal());  | 
            |
| 1259 | 
                - }  | 
            |
| 1260 | 
                - return null;  | 
            |
| 1261 | 
                - }  | 
            |
| 1262 | 
                -  | 
            |
| 1263 | 
                - /**  | 
            |
| 1264 | 
                - * @return all bottomViews: left, top, right, bottom (may null if the edge is not set)  | 
            |
| 1265 | 
                - */  | 
            |
| 1266 | 
                -    public List<View> getBottomViews() {
               | 
            |
| 1267 | 
                - ArrayList<View> bottoms = new ArrayList<View>();  | 
            |
| 1268 | 
                -        for (DragEdge dragEdge : DragEdge.values()) {
               | 
            |
| 1269 | 
                - bottoms.add(mDragEdges.get(dragEdge));  | 
            |
| 1270 | 
                - }  | 
            |
| 1271 | 
                - return bottoms;  | 
            |
| 1272 | 
                - }  | 
            |
| 1273 | 
                -  | 
            |
| 1274 | 
                -    public enum Status {
               | 
            |
| 1275 | 
                - Middle,  | 
            |
| 1276 | 
                - Open,  | 
            |
| 1277 | 
                - Close  | 
            |
| 1278 | 
                - }  | 
            |
| 1279 | 
                -  | 
            |
| 1280 | 
                - /**  | 
            |
| 1281 | 
                - * get the open status.  | 
            |
| 1282 | 
                - *  | 
            |
| 1283 | 
                - */  | 
            |
| 1284 | 
                -    public Status getOpenStatus() {
               | 
            |
| 1285 | 
                - View surfaceView = getSurfaceView();  | 
            |
| 1286 | 
                -        if (surfaceView == null) {
               | 
            |
| 1287 | 
                - return Status.Close;  | 
            |
| 1288 | 
                - }  | 
            |
| 1289 | 
                - int surfaceLeft = surfaceView.getLeft();  | 
            |
| 1290 | 
                - int surfaceTop = surfaceView.getTop();  | 
            |
| 1291 | 
                - if (surfaceLeft == getPaddingLeft() && surfaceTop == getPaddingTop()) return Status.Close;  | 
            |
| 1292 | 
                -  | 
            |
| 1293 | 
                - if (surfaceLeft == (getPaddingLeft() - mDragDistance) || surfaceLeft == (getPaddingLeft() + mDragDistance)  | 
            |
| 1294 | 
                - || surfaceTop == (getPaddingTop() - mDragDistance) || surfaceTop == (getPaddingTop() + mDragDistance))  | 
            |
| 1295 | 
                - return Status.Open;  | 
            |
| 1296 | 
                -  | 
            |
| 1297 | 
                - return Status.Middle;  | 
            |
| 1298 | 
                - }  | 
            |
| 1299 | 
                -  | 
            |
| 1300 | 
                -  | 
            |
| 1301 | 
                - /**  | 
            |
| 1302 | 
                - * Process the surface release event.  | 
            |
| 1303 | 
                - *  | 
            |
| 1304 | 
                - * @param xvel xVelocity  | 
            |
| 1305 | 
                - * @param yvel yVelocity  | 
            |
| 1306 | 
                - * @param isCloseBeforeDragged the open state before drag  | 
            |
| 1307 | 
                - */  | 
            |
| 1308 | 
                -    protected void processHandRelease(float xvel, float yvel, boolean isCloseBeforeDragged) {
               | 
            |
| 1309 | 
                - float minVelocity = mDragHelper.getMinVelocity();  | 
            |
| 1310 | 
                - View surfaceView = getSurfaceView();  | 
            |
| 1311 | 
                - DragEdge currentDragEdge = mCurrentDragEdge;  | 
            |
| 1312 | 
                -        if (currentDragEdge == null || surfaceView == null) {
               | 
            |
| 1313 | 
                - return;  | 
            |
| 1314 | 
                - }  | 
            |
| 1315 | 
                - float willOpenPercent = (isCloseBeforeDragged ? mWillOpenPercentAfterClose : mWillOpenPercentAfterOpen);  | 
            |
| 1316 | 
                -        if (currentDragEdge == DragEdge.Left) {
               | 
            |
| 1317 | 
                - if (xvel > minVelocity) open();  | 
            |
| 1318 | 
                - else if (xvel < -minVelocity) close();  | 
            |
| 1319 | 
                -            else {
               | 
            |
| 1320 | 
                - float openPercent = 1f * getSurfaceView().getLeft() / mDragDistance;  | 
            |
| 1321 | 
                - if (openPercent > willOpenPercent) open();  | 
            |
| 1322 | 
                - else close();  | 
            |
| 1323 | 
                - }  | 
            |
| 1324 | 
                -        } else if (currentDragEdge == DragEdge.Right) {
               | 
            |
| 1325 | 
                - if (xvel > minVelocity) close();  | 
            |
| 1326 | 
                - else if (xvel < -minVelocity) open();  | 
            |
| 1327 | 
                -            else {
               | 
            |
| 1328 | 
                - float openPercent = 1f * (-getSurfaceView().getLeft()) / mDragDistance;  | 
            |
| 1329 | 
                - if (openPercent > willOpenPercent) open();  | 
            |
| 1330 | 
                - else close();  | 
            |
| 1331 | 
                - }  | 
            |
| 1332 | 
                -        } else if (currentDragEdge == DragEdge.Top) {
               | 
            |
| 1333 | 
                - if (yvel > minVelocity) open();  | 
            |
| 1334 | 
                - else if (yvel < -minVelocity) close();  | 
            |
| 1335 | 
                -            else {
               | 
            |
| 1336 | 
                - float openPercent = 1f * getSurfaceView().getTop() / mDragDistance;  | 
            |
| 1337 | 
                - if (openPercent > willOpenPercent) open();  | 
            |
| 1338 | 
                - else close();  | 
            |
| 1339 | 
                - }  | 
            |
| 1340 | 
                -        } else if (currentDragEdge == DragEdge.Bottom) {
               | 
            |
| 1341 | 
                - if (yvel > minVelocity) close();  | 
            |
| 1342 | 
                - else if (yvel < -minVelocity) open();  | 
            |
| 1343 | 
                -            else {
               | 
            |
| 1344 | 
                - float openPercent = 1f * (-getSurfaceView().getTop()) / mDragDistance;  | 
            |
| 1345 | 
                - if (openPercent > willOpenPercent) open();  | 
            |
| 1346 | 
                - else close();  | 
            |
| 1347 | 
                - }  | 
            |
| 1348 | 
                - }  | 
            |
| 1349 | 
                - }  | 
            |
| 1350 | 
                -  | 
            |
| 1351 | 
                - /**  | 
            |
| 1352 | 
                - * smoothly open surface.  | 
            |
| 1353 | 
                - */  | 
            |
| 1354 | 
                -    public void open() {
               | 
            |
| 1355 | 
                - open(true, true);  | 
            |
| 1356 | 
                - }  | 
            |
| 1357 | 
                -  | 
            |
| 1358 | 
                -    public void open(boolean smooth) {
               | 
            |
| 1359 | 
                - open(smooth, true);  | 
            |
| 1360 | 
                - }  | 
            |
| 1361 | 
                -  | 
            |
| 1362 | 
                -    public void open(boolean smooth, boolean notify) {
               | 
            |
| 1363 | 
                - View surface = getSurfaceView(), bottom = getCurrentBottomView();  | 
            |
| 1364 | 
                -        if (surface == null) {
               | 
            |
| 1365 | 
                - return;  | 
            |
| 1366 | 
                - }  | 
            |
| 1367 | 
                - int dx, dy;  | 
            |
| 1368 | 
                - Rect rect = computeSurfaceLayoutArea(true);  | 
            |
| 1369 | 
                -        if (smooth) {
               | 
            |
| 1370 | 
                - mDragHelper.smoothSlideViewTo(surface, rect.left, rect.top);  | 
            |
| 1371 | 
                -        } else {
               | 
            |
| 1372 | 
                - dx = rect.left - surface.getLeft();  | 
            |
| 1373 | 
                - dy = rect.top - surface.getTop();  | 
            |
| 1374 | 
                - surface.layout(rect.left, rect.top, rect.right, rect.bottom);  | 
            |
| 1375 | 
                -            if (getShowMode() == ShowMode.PullOut) {
               | 
            |
| 1376 | 
                - Rect bRect = computeBottomLayoutAreaViaSurface(ShowMode.PullOut, rect);  | 
            |
| 1377 | 
                -                if (bottom != null) {
               | 
            |
| 1378 | 
                - bottom.layout(bRect.left, bRect.top, bRect.right, bRect.bottom);  | 
            |
| 1379 | 
                - }  | 
            |
| 1380 | 
                - }  | 
            |
| 1381 | 
                -            if (notify) {
               | 
            |
| 1382 | 
                - dispatchRevealEvent(rect.left, rect.top, rect.right, rect.bottom);  | 
            |
| 1383 | 
                - dispatchSwipeEvent(rect.left, rect.top, dx, dy);  | 
            |
| 1384 | 
                -            } else {
               | 
            |
| 1385 | 
                - safeBottomView();  | 
            |
| 1386 | 
                - }  | 
            |
| 1387 | 
                - }  | 
            |
| 1388 | 
                - invalidate();  | 
            |
| 1389 | 
                - }  | 
            |
| 1390 | 
                -  | 
            |
| 1391 | 
                -    public void open(DragEdge edge) {
               | 
            |
| 1392 | 
                - setCurrentDragEdge(edge);  | 
            |
| 1393 | 
                - open(true, true);  | 
            |
| 1394 | 
                - }  | 
            |
| 1395 | 
                -  | 
            |
| 1396 | 
                -    public void open(boolean smooth, DragEdge edge) {
               | 
            |
| 1397 | 
                - setCurrentDragEdge(edge);  | 
            |
| 1398 | 
                - open(smooth, true);  | 
            |
| 1399 | 
                - }  | 
            |
| 1400 | 
                -  | 
            |
| 1401 | 
                -    public void open(boolean smooth, boolean notify, DragEdge edge) {
               | 
            |
| 1402 | 
                - setCurrentDragEdge(edge);  | 
            |
| 1403 | 
                - open(smooth, notify);  | 
            |
| 1404 | 
                - }  | 
            |
| 1405 | 
                -  | 
            |
| 1406 | 
                - /**  | 
            |
| 1407 | 
                - * smoothly close surface.  | 
            |
| 1408 | 
                - */  | 
            |
| 1409 | 
                -    public void close() {
               | 
            |
| 1410 | 
                - close(true, true);  | 
            |
| 1411 | 
                - }  | 
            |
| 1412 | 
                -  | 
            |
| 1413 | 
                -    public void close(boolean smooth) {
               | 
            |
| 1414 | 
                - close(smooth, true);  | 
            |
| 1415 | 
                - }  | 
            |
| 1416 | 
                -  | 
            |
| 1417 | 
                - /**  | 
            |
| 1418 | 
                - * close surface  | 
            |
| 1419 | 
                - *  | 
            |
| 1420 | 
                - * @param smooth smoothly or not.  | 
            |
| 1421 | 
                - * @param notify if notify all the listeners.  | 
            |
| 1422 | 
                - */  | 
            |
| 1423 | 
                -    public void close(boolean smooth, boolean notify) {
               | 
            |
| 1424 | 
                - View surface = getSurfaceView();  | 
            |
| 1425 | 
                -        if (surface == null) {
               | 
            |
| 1426 | 
                - return;  | 
            |
| 1427 | 
                - }  | 
            |
| 1428 | 
                - int dx, dy;  | 
            |
| 1429 | 
                - if (smooth)  | 
            |
| 1430 | 
                - mDragHelper.smoothSlideViewTo(getSurfaceView(), getPaddingLeft(), getPaddingTop());  | 
            |
| 1431 | 
                -        else {
               | 
            |
| 1432 | 
                - Rect rect = computeSurfaceLayoutArea(false);  | 
            |
| 1433 | 
                - dx = rect.left - surface.getLeft();  | 
            |
| 1434 | 
                - dy = rect.top - surface.getTop();  | 
            |
| 1435 | 
                - surface.layout(rect.left, rect.top, rect.right, rect.bottom);  | 
            |
| 1436 | 
                -            if (notify) {
               | 
            |
| 1437 | 
                - dispatchRevealEvent(rect.left, rect.top, rect.right, rect.bottom);  | 
            |
| 1438 | 
                - dispatchSwipeEvent(rect.left, rect.top, dx, dy);  | 
            |
| 1439 | 
                -            } else {
               | 
            |
| 1440 | 
                - safeBottomView();  | 
            |
| 1441 | 
                - }  | 
            |
| 1442 | 
                - }  | 
            |
| 1443 | 
                - invalidate();  | 
            |
| 1444 | 
                - }  | 
            |
| 1445 | 
                -  | 
            |
| 1446 | 
                -    public void toggle() {
               | 
            |
| 1447 | 
                - toggle(true);  | 
            |
| 1448 | 
                - }  | 
            |
| 1449 | 
                -  | 
            |
| 1450 | 
                -    public void toggle(boolean smooth) {
               | 
            |
| 1451 | 
                - if (getOpenStatus() == Status.Open)  | 
            |
| 1452 | 
                - close(smooth);  | 
            |
| 1453 | 
                - else if (getOpenStatus() == Status.Close) open(smooth);  | 
            |
| 1454 | 
                - }  | 
            |
| 1455 | 
                -  | 
            |
| 1456 | 
                -  | 
            |
| 1457 | 
                - /**  | 
            |
| 1458 | 
                - * a helper function to compute the Rect area that surface will hold in.  | 
            |
| 1459 | 
                - *  | 
            |
| 1460 | 
                - * @param open open status or close status.  | 
            |
| 1461 | 
                - */  | 
            |
| 1462 | 
                -    private Rect computeSurfaceLayoutArea(boolean open) {
               | 
            |
| 1463 | 
                - int l = getPaddingLeft(), t = getPaddingTop();  | 
            |
| 1464 | 
                -        if (open) {
               | 
            |
| 1465 | 
                - if (mCurrentDragEdge == DragEdge.Left)  | 
            |
| 1466 | 
                - l = getPaddingLeft() + mDragDistance;  | 
            |
| 1467 | 
                - else if (mCurrentDragEdge == DragEdge.Right)  | 
            |
| 1468 | 
                - l = getPaddingLeft() - mDragDistance;  | 
            |
| 1469 | 
                - else if (mCurrentDragEdge == DragEdge.Top)  | 
            |
| 1470 | 
                - t = getPaddingTop() + mDragDistance;  | 
            |
| 1471 | 
                - else t = getPaddingTop() - mDragDistance;  | 
            |
| 1472 | 
                - }  | 
            |
| 1473 | 
                - return new Rect(l, t, l + getMeasuredWidth(), t + getMeasuredHeight());  | 
            |
| 1474 | 
                - }  | 
            |
| 1475 | 
                -  | 
            |
| 1476 | 
                -    private Rect computeBottomLayoutAreaViaSurface(ShowMode mode, Rect surfaceArea) {
               | 
            |
| 1477 | 
                - Rect rect = surfaceArea;  | 
            |
| 1478 | 
                - View bottomView = getCurrentBottomView();  | 
            |
| 1479 | 
                -  | 
            |
| 1480 | 
                - int bl = rect.left, bt = rect.top, br = rect.right, bb = rect.bottom;  | 
            |
| 1481 | 
                -        if (mode == ShowMode.PullOut) {
               | 
            |
| 1482 | 
                - if (mCurrentDragEdge == DragEdge.Left)  | 
            |
| 1483 | 
                - bl = rect.left - mDragDistance;  | 
            |
| 1484 | 
                - else if (mCurrentDragEdge == DragEdge.Right)  | 
            |
| 1485 | 
                - bl = rect.right;  | 
            |
| 1486 | 
                - else if (mCurrentDragEdge == DragEdge.Top)  | 
            |
| 1487 | 
                - bt = rect.top - mDragDistance;  | 
            |
| 1488 | 
                - else bt = rect.bottom;  | 
            |
| 1489 | 
                -  | 
            |
| 1490 | 
                -            if (mCurrentDragEdge == DragEdge.Left || mCurrentDragEdge == DragEdge.Right) {
               | 
            |
| 1491 | 
                - bb = rect.bottom;  | 
            |
| 1492 | 
                - br = bl + (bottomView == null ? 0 : bottomView.getMeasuredWidth());  | 
            |
| 1493 | 
                -            } else {
               | 
            |
| 1494 | 
                - bb = bt + (bottomView == null ? 0 : bottomView.getMeasuredHeight());  | 
            |
| 1495 | 
                - br = rect.right;  | 
            |
| 1496 | 
                - }  | 
            |
| 1497 | 
                -        } else if (mode == ShowMode.LayDown) {
               | 
            |
| 1498 | 
                - if (mCurrentDragEdge == DragEdge.Left)  | 
            |
| 1499 | 
                - br = bl + mDragDistance;  | 
            |
| 1500 | 
                - else if (mCurrentDragEdge == DragEdge.Right)  | 
            |
| 1501 | 
                - bl = br - mDragDistance;  | 
            |
| 1502 | 
                - else if (mCurrentDragEdge == DragEdge.Top)  | 
            |
| 1503 | 
                - bb = bt + mDragDistance;  | 
            |
| 1504 | 
                - else bt = bb - mDragDistance;  | 
            |
| 1505 | 
                -  | 
            |
| 1506 | 
                - }  | 
            |
| 1507 | 
                - return new Rect(bl, bt, br, bb);  | 
            |
| 1508 | 
                -  | 
            |
| 1509 | 
                - }  | 
            |
| 1510 | 
                -  | 
            |
| 1511 | 
                -    private Rect computeBottomLayDown(DragEdge dragEdge) {
               | 
            |
| 1512 | 
                - int bl = getPaddingLeft(), bt = getPaddingTop();  | 
            |
| 1513 | 
                - int br, bb;  | 
            |
| 1514 | 
                -        if (dragEdge == DragEdge.Right) {
               | 
            |
| 1515 | 
                - bl = getMeasuredWidth() - mDragDistance;  | 
            |
| 1516 | 
                -        } else if (dragEdge == DragEdge.Bottom) {
               | 
            |
| 1517 | 
                - bt = getMeasuredHeight() - mDragDistance;  | 
            |
| 1518 | 
                - }  | 
            |
| 1519 | 
                -        if (dragEdge == DragEdge.Left || dragEdge == DragEdge.Right) {
               | 
            |
| 1520 | 
                - br = bl + mDragDistance;  | 
            |
| 1521 | 
                - bb = bt + getMeasuredHeight();  | 
            |
| 1522 | 
                -        } else {
               | 
            |
| 1523 | 
                - br = bl + getMeasuredWidth();  | 
            |
| 1524 | 
                - bb = bt + mDragDistance;  | 
            |
| 1525 | 
                - }  | 
            |
| 1526 | 
                - return new Rect(bl, bt, br, bb);  | 
            |
| 1527 | 
                - }  | 
            |
| 1528 | 
                -  | 
            |
| 1529 | 
                -    public void setOnDoubleClickListener(DoubleClickListener doubleClickListener) {
               | 
            |
| 1530 | 
                - mDoubleClickListener = doubleClickListener;  | 
            |
| 1531 | 
                - }  | 
            |
| 1532 | 
                -  | 
            |
| 1533 | 
                -    public interface DoubleClickListener {
               | 
            |
| 1534 | 
                - void onDoubleClick(SwipeLayout layout, boolean surface);  | 
            |
| 1535 | 
                - }  | 
            |
| 1536 | 
                -  | 
            |
| 1537 | 
                -    private int dp2px(float dp) {
               | 
            |
| 1538 | 
                - return (int) (dp * getContext().getResources().getDisplayMetrics().density + 0.5f);  | 
            |
| 1539 | 
                - }  | 
            |
| 1540 | 
                -  | 
            |
| 1541 | 
                -  | 
            |
| 1542 | 
                - /**  | 
            |
| 1543 | 
                -     * Deprecated, use {@link #setDrag(DragEdge, View)}
               | 
            |
| 1544 | 
                - */  | 
            |
| 1545 | 
                - @Deprecated  | 
            |
| 1546 | 
                -    public void setDragEdge(DragEdge dragEdge) {
               | 
            |
| 1547 | 
                - clearDragEdge();  | 
            |
| 1548 | 
                -        if (getChildCount() >= 2) {
               | 
            |
| 1549 | 
                - mDragEdges.put(dragEdge, getChildAt(getChildCount() - 2));  | 
            |
| 1550 | 
                - }  | 
            |
| 1551 | 
                - setCurrentDragEdge(dragEdge);  | 
            |
| 1552 | 
                - }  | 
            |
| 1553 | 
                -  | 
            |
| 1554 | 
                -    public void onViewRemoved(View child) {
               | 
            |
| 1555 | 
                -        for (Map.Entry<DragEdge, View> entry : new HashMap<DragEdge, View>(mDragEdges).entrySet()) {
               | 
            |
| 1556 | 
                -            if (entry.getValue() == child) {
               | 
            |
| 1557 | 
                - mDragEdges.remove(entry.getKey());  | 
            |
| 1558 | 
                - }  | 
            |
| 1559 | 
                - }  | 
            |
| 1560 | 
                - }  | 
            |
| 1561 | 
                -  | 
            |
| 1562 | 
                -    public Map<DragEdge, View> getDragEdgeMap() {
               | 
            |
| 1563 | 
                - return mDragEdges;  | 
            |
| 1564 | 
                - }  | 
            |
| 1565 | 
                -  | 
            |
| 1566 | 
                - /**  | 
            |
| 1567 | 
                -     * Deprecated, use {@link #getDragEdgeMap()}
               | 
            |
| 1568 | 
                - */  | 
            |
| 1569 | 
                - @Deprecated  | 
            |
| 1570 | 
                -    public List<DragEdge> getDragEdges() {
               | 
            |
| 1571 | 
                - return new ArrayList<DragEdge>(mDragEdges.keySet());  | 
            |
| 1572 | 
                - }  | 
            |
| 1573 | 
                -  | 
            |
| 1574 | 
                - /**  | 
            |
| 1575 | 
                -     * Deprecated, use {@link #setDrag(DragEdge, View)}
               | 
            |
| 1576 | 
                - */  | 
            |
| 1577 | 
                - @Deprecated  | 
            |
| 1578 | 
                -    public void setDragEdges(List<DragEdge> dragEdges) {
               | 
            |
| 1579 | 
                - clearDragEdge();  | 
            |
| 1580 | 
                -        for (int i = 0, size = Math.min(dragEdges.size(), getChildCount() - 1); i < size; i++) {
               | 
            |
| 1581 | 
                - DragEdge dragEdge = dragEdges.get(i);  | 
            |
| 1582 | 
                - mDragEdges.put(dragEdge, getChildAt(i));  | 
            |
| 1583 | 
                - }  | 
            |
| 1584 | 
                -        if (dragEdges.size() == 0 || dragEdges.contains(DefaultDragEdge)) {
               | 
            |
| 1585 | 
                - setCurrentDragEdge(DefaultDragEdge);  | 
            |
| 1586 | 
                -        } else {
               | 
            |
| 1587 | 
                - setCurrentDragEdge(dragEdges.get(0));  | 
            |
| 1588 | 
                - }  | 
            |
| 1589 | 
                - }  | 
            |
| 1590 | 
                -  | 
            |
| 1591 | 
                - /**  | 
            |
| 1592 | 
                -     * Deprecated, use {@link #addDrag(DragEdge, View)}
               | 
            |
| 1593 | 
                - */  | 
            |
| 1594 | 
                - @Deprecated  | 
            |
| 1595 | 
                -    public void setDragEdges(DragEdge... mDragEdges) {
               | 
            |
| 1596 | 
                - clearDragEdge();  | 
            |
| 1597 | 
                - setDragEdges(Arrays.asList(mDragEdges));  | 
            |
| 1598 | 
                - }  | 
            |
| 1599 | 
                -  | 
            |
| 1600 | 
                - /**  | 
            |
| 1601 | 
                -     * Deprecated, use {@link #addDrag(DragEdge, View)}
               | 
            |
| 1602 | 
                - * When using multiple drag edges it's a good idea to pass the ids of the views that  | 
            |
| 1603 | 
                - * you're using for the left, right, top bottom views (-1 if you're not using a particular view)  | 
            |
| 1604 | 
                - */  | 
            |
| 1605 | 
                - @Deprecated  | 
            |
| 1606 | 
                -    public void setBottomViewIds(int leftId, int rightId, int topId, int bottomId) {
               | 
            |
| 1607 | 
                - addDrag(DragEdge.Left, findViewById(leftId));  | 
            |
| 1608 | 
                - addDrag(DragEdge.Right, findViewById(rightId));  | 
            |
| 1609 | 
                - addDrag(DragEdge.Top, findViewById(topId));  | 
            |
| 1610 | 
                - addDrag(DragEdge.Bottom, findViewById(bottomId));  | 
            |
| 1611 | 
                - }  | 
            |
| 1612 | 
                -  | 
            |
| 1613 | 
                -    private float getCurrentOffset() {
               | 
            |
| 1614 | 
                - if (mCurrentDragEdge == null) return 0;  | 
            |
| 1615 | 
                - return mEdgeSwipesOffset[mCurrentDragEdge.ordinal()];  | 
            |
| 1616 | 
                - }  | 
            |
| 1617 | 
                -  | 
            |
| 1618 | 
                -    private void setCurrentDragEdge(DragEdge dragEdge) {
               | 
            |
| 1619 | 
                - mCurrentDragEdge = dragEdge;  | 
            |
| 1620 | 
                - updateBottomViews();  | 
            |
| 1621 | 
                - }  | 
            |
| 1622 | 
                -  | 
            |
| 1623 | 
                -    private void updateBottomViews() {
               | 
            |
| 1624 | 
                - View currentBottomView = getCurrentBottomView();  | 
            |
| 1625 | 
                -        if (currentBottomView != null) {
               | 
            |
| 1626 | 
                -            if (mCurrentDragEdge == DragEdge.Left || mCurrentDragEdge == DragEdge.Right) {
               | 
            |
| 1627 | 
                - mDragDistance = currentBottomView.getMeasuredWidth() - dp2px(getCurrentOffset());  | 
            |
| 1628 | 
                -            } else {
               | 
            |
| 1629 | 
                - mDragDistance = currentBottomView.getMeasuredHeight() - dp2px(getCurrentOffset());  | 
            |
| 1630 | 
                - }  | 
            |
| 1631 | 
                - }  | 
            |
| 1632 | 
                -  | 
            |
| 1633 | 
                -        if (mShowMode == ShowMode.PullOut) {
               | 
            |
| 1634 | 
                - layoutPullOut();  | 
            |
| 1635 | 
                -        } else if (mShowMode == ShowMode.LayDown) {
               | 
            |
| 1636 | 
                - layoutLayDown();  | 
            |
| 1637 | 
                - }  | 
            |
| 1638 | 
                -  | 
            |
| 1639 | 
                - safeBottomView();  | 
            |
| 1640 | 
                - }  | 
            |
| 1641 | 
                -}  | 
            
                @@ -0,0 +1,19 @@  | 
            ||
| 1 | 
                +package com.android.views.swipebacklayout;  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +/**  | 
            |
| 4 | 
                + * @author Yrom  | 
            |
| 5 | 
                + */  | 
            |
| 6 | 
                +public interface SwipeBackActivityBase {
               | 
            |
| 7 | 
                + /**  | 
            |
| 8 | 
                + * @return the SwipeBackLayout associated with this activity.  | 
            |
| 9 | 
                + */  | 
            |
| 10 | 
                + public abstract SwipeBackLayout getSwipeBackLayout();  | 
            |
| 11 | 
                +  | 
            |
| 12 | 
                + public abstract void setSwipeBackEnable(boolean enable);  | 
            |
| 13 | 
                +  | 
            |
| 14 | 
                + /**  | 
            |
| 15 | 
                + * Scroll out contentView and finish the activity  | 
            |
| 16 | 
                + */  | 
            |
| 17 | 
                + public abstract void scrollToFinishActivity();  | 
            |
| 18 | 
                +  | 
            |
| 19 | 
                +}  | 
            
                @@ -0,0 +1,60 @@  | 
            ||
| 1 | 
                +package com.android.views.swipebacklayout;  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +import android.app.Activity;  | 
            |
| 4 | 
                +import android.graphics.Color;  | 
            |
| 5 | 
                +import android.graphics.drawable.ColorDrawable;  | 
            |
| 6 | 
                +import android.view.LayoutInflater;  | 
            |
| 7 | 
                +import android.view.View;  | 
            |
| 8 | 
                +  | 
            |
| 9 | 
                +import com.android.views.R;  | 
            |
| 10 | 
                +  | 
            |
| 11 | 
                +/**  | 
            |
| 12 | 
                + * @author Yrom  | 
            |
| 13 | 
                + */  | 
            |
| 14 | 
                +public class SwipeBackActivityHelper {
               | 
            |
| 15 | 
                + private Activity mActivity;  | 
            |
| 16 | 
                +  | 
            |
| 17 | 
                + private SwipeBackLayout mSwipeBackLayout;  | 
            |
| 18 | 
                +  | 
            |
| 19 | 
                +    public SwipeBackActivityHelper(Activity activity) {
               | 
            |
| 20 | 
                + mActivity = activity;  | 
            |
| 21 | 
                + }  | 
            |
| 22 | 
                +  | 
            |
| 23 | 
                +    @SuppressWarnings("deprecation")
               | 
            |
| 24 | 
                +    public void onActivityCreate() {
               | 
            |
| 25 | 
                + mActivity.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));  | 
            |
| 26 | 
                + mActivity.getWindow().getDecorView().setBackgroundDrawable(null);  | 
            |
| 27 | 
                + mSwipeBackLayout = (SwipeBackLayout) LayoutInflater.from(mActivity).inflate(  | 
            |
| 28 | 
                + R.layout.swipeback_layout, null);  | 
            |
| 29 | 
                +        mSwipeBackLayout.addSwipeListener(new SwipeBackLayout.SwipeListener() {
               | 
            |
| 30 | 
                + @Override  | 
            |
| 31 | 
                +            public void onScrollStateChange(int state, float scrollPercent) {
               | 
            |
| 32 | 
                + }  | 
            |
| 33 | 
                +  | 
            |
| 34 | 
                + @Override  | 
            |
| 35 | 
                +            public void onEdgeTouch(int edgeFlag) {
               | 
            |
| 36 | 
                + Utils.convertActivityToTranslucent(mActivity);  | 
            |
| 37 | 
                + }  | 
            |
| 38 | 
                +  | 
            |
| 39 | 
                + @Override  | 
            |
| 40 | 
                +            public void onScrollOverThreshold() {
               | 
            |
| 41 | 
                +  | 
            |
| 42 | 
                + }  | 
            |
| 43 | 
                + });  | 
            |
| 44 | 
                + }  | 
            |
| 45 | 
                +  | 
            |
| 46 | 
                +    public void onPostCreate() {
               | 
            |
| 47 | 
                + mSwipeBackLayout.attachToActivity(mActivity);  | 
            |
| 48 | 
                + }  | 
            |
| 49 | 
                +  | 
            |
| 50 | 
                +    public View findViewById(int id) {
               | 
            |
| 51 | 
                +        if (mSwipeBackLayout != null) {
               | 
            |
| 52 | 
                + return mSwipeBackLayout.findViewById(id);  | 
            |
| 53 | 
                + }  | 
            |
| 54 | 
                + return null;  | 
            |
| 55 | 
                + }  | 
            |
| 56 | 
                +  | 
            |
| 57 | 
                +    public SwipeBackLayout getSwipeBackLayout() {
               | 
            |
| 58 | 
                + return mSwipeBackLayout;  | 
            |
| 59 | 
                + }  | 
            |
| 60 | 
                +}  | 
            
                @@ -0,0 +1,606 @@  | 
            ||
| 1 | 
                +package com.android.views.swipebacklayout;  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +import android.app.Activity;  | 
            |
| 4 | 
                +import android.content.Context;  | 
            |
| 5 | 
                +import android.content.res.TypedArray;  | 
            |
| 6 | 
                +import android.graphics.Canvas;  | 
            |
| 7 | 
                +import android.graphics.Rect;  | 
            |
| 8 | 
                +import android.graphics.drawable.Drawable;  | 
            |
| 9 | 
                +import android.support.v4.view.ViewCompat;  | 
            |
| 10 | 
                +import android.util.AttributeSet;  | 
            |
| 11 | 
                +import android.view.MotionEvent;  | 
            |
| 12 | 
                +import android.view.View;  | 
            |
| 13 | 
                +import android.view.ViewGroup;  | 
            |
| 14 | 
                +import android.widget.FrameLayout;  | 
            |
| 15 | 
                +  | 
            |
| 16 | 
                +import com.android.views.R;  | 
            |
| 17 | 
                +  | 
            |
| 18 | 
                +import java.util.ArrayList;  | 
            |
| 19 | 
                +import java.util.List;  | 
            |
| 20 | 
                +  | 
            |
| 21 | 
                +  | 
            |
| 22 | 
                +public class SwipeBackLayout extends FrameLayout {
               | 
            |
| 23 | 
                + /**  | 
            |
| 24 | 
                + * Minimum velocity that will be detected as a fling  | 
            |
| 25 | 
                + */  | 
            |
| 26 | 
                + private static final int MIN_FLING_VELOCITY = 400; // dips per second  | 
            |
| 27 | 
                +  | 
            |
| 28 | 
                + private static final int DEFAULT_SCRIM_COLOR = 0x99000000;  | 
            |
| 29 | 
                +  | 
            |
| 30 | 
                + private static final int FULL_ALPHA = 255;  | 
            |
| 31 | 
                +  | 
            |
| 32 | 
                + /**  | 
            |
| 33 | 
                + * Edge flag indicating that the left edge should be affected.  | 
            |
| 34 | 
                + */  | 
            |
| 35 | 
                + public static final int EDGE_LEFT = ViewDragHelper.EDGE_LEFT;  | 
            |
| 36 | 
                +  | 
            |
| 37 | 
                + /**  | 
            |
| 38 | 
                + * Edge flag indicating that the right edge should be affected.  | 
            |
| 39 | 
                + */  | 
            |
| 40 | 
                + public static final int EDGE_RIGHT = ViewDragHelper.EDGE_RIGHT;  | 
            |
| 41 | 
                +  | 
            |
| 42 | 
                + /**  | 
            |
| 43 | 
                + * Edge flag indicating that the bottom edge should be affected.  | 
            |
| 44 | 
                + */  | 
            |
| 45 | 
                + public static final int EDGE_BOTTOM = ViewDragHelper.EDGE_BOTTOM;  | 
            |
| 46 | 
                +  | 
            |
| 47 | 
                + /**  | 
            |
| 48 | 
                + * Edge flag set indicating all edges should be affected.  | 
            |
| 49 | 
                + */  | 
            |
| 50 | 
                + public static final int EDGE_ALL = EDGE_LEFT | EDGE_RIGHT | EDGE_BOTTOM;  | 
            |
| 51 | 
                +  | 
            |
| 52 | 
                + /**  | 
            |
| 53 | 
                + * A view is not currently being dragged or animating as a result of a  | 
            |
| 54 | 
                + * fling/snap.  | 
            |
| 55 | 
                + */  | 
            |
| 56 | 
                + public static final int STATE_IDLE = ViewDragHelper.STATE_IDLE;  | 
            |
| 57 | 
                +  | 
            |
| 58 | 
                + /**  | 
            |
| 59 | 
                + * A view is currently being dragged. The position is currently changing as  | 
            |
| 60 | 
                + * a result of user input or simulated user input.  | 
            |
| 61 | 
                + */  | 
            |
| 62 | 
                + public static final int STATE_DRAGGING = ViewDragHelper.STATE_DRAGGING;  | 
            |
| 63 | 
                +  | 
            |
| 64 | 
                + /**  | 
            |
| 65 | 
                + * A view is currently settling into place as a result of a fling or  | 
            |
| 66 | 
                + * predefined non-interactive motion.  | 
            |
| 67 | 
                + */  | 
            |
| 68 | 
                + public static final int STATE_SETTLING = ViewDragHelper.STATE_SETTLING;  | 
            |
| 69 | 
                +  | 
            |
| 70 | 
                + /**  | 
            |
| 71 | 
                + * Default threshold of scroll  | 
            |
| 72 | 
                + */  | 
            |
| 73 | 
                + private static final float DEFAULT_SCROLL_THRESHOLD = 0.3f;  | 
            |
| 74 | 
                +  | 
            |
| 75 | 
                + private static final int OVERSCROLL_DISTANCE = 10;  | 
            |
| 76 | 
                +  | 
            |
| 77 | 
                +    private static final int[] EDGE_FLAGS = {
               | 
            |
| 78 | 
                + EDGE_LEFT, EDGE_RIGHT, EDGE_BOTTOM, EDGE_ALL  | 
            |
| 79 | 
                + };  | 
            |
| 80 | 
                +  | 
            |
| 81 | 
                + private int mEdgeFlag;  | 
            |
| 82 | 
                +  | 
            |
| 83 | 
                + /**  | 
            |
| 84 | 
                + * Threshold of scroll, we will close the activity, when scrollPercent over  | 
            |
| 85 | 
                + * this value;  | 
            |
| 86 | 
                + */  | 
            |
| 87 | 
                + private float mScrollThreshold = DEFAULT_SCROLL_THRESHOLD;  | 
            |
| 88 | 
                +  | 
            |
| 89 | 
                + private Activity mActivity;  | 
            |
| 90 | 
                +  | 
            |
| 91 | 
                + private boolean mEnable = true;  | 
            |
| 92 | 
                +  | 
            |
| 93 | 
                + private View mContentView;  | 
            |
| 94 | 
                +  | 
            |
| 95 | 
                + private ViewDragHelper mDragHelper;  | 
            |
| 96 | 
                +  | 
            |
| 97 | 
                + private float mScrollPercent;  | 
            |
| 98 | 
                +  | 
            |
| 99 | 
                + private int mContentLeft;  | 
            |
| 100 | 
                +  | 
            |
| 101 | 
                + private int mContentTop;  | 
            |
| 102 | 
                +  | 
            |
| 103 | 
                + /**  | 
            |
| 104 | 
                + * The set of listeners to be sent events through.  | 
            |
| 105 | 
                + */  | 
            |
| 106 | 
                + private List<SwipeListener> mListeners;  | 
            |
| 107 | 
                +  | 
            |
| 108 | 
                + private Drawable mShadowLeft;  | 
            |
| 109 | 
                +  | 
            |
| 110 | 
                + private Drawable mShadowRight;  | 
            |
| 111 | 
                +  | 
            |
| 112 | 
                + private Drawable mShadowBottom;  | 
            |
| 113 | 
                +  | 
            |
| 114 | 
                + private float mScrimOpacity;  | 
            |
| 115 | 
                +  | 
            |
| 116 | 
                + private int mScrimColor = DEFAULT_SCRIM_COLOR;  | 
            |
| 117 | 
                +  | 
            |
| 118 | 
                + private boolean mInLayout;  | 
            |
| 119 | 
                +  | 
            |
| 120 | 
                + private Rect mTmpRect = new Rect();  | 
            |
| 121 | 
                +  | 
            |
| 122 | 
                + /**  | 
            |
| 123 | 
                + * Edge being dragged  | 
            |
| 124 | 
                + */  | 
            |
| 125 | 
                + private int mTrackingEdge;  | 
            |
| 126 | 
                +  | 
            |
| 127 | 
                +    public SwipeBackLayout(Context context) {
               | 
            |
| 128 | 
                + this(context, null);  | 
            |
| 129 | 
                + }  | 
            |
| 130 | 
                +  | 
            |
| 131 | 
                +    public SwipeBackLayout(Context context, AttributeSet attrs) {
               | 
            |
| 132 | 
                + this(context, attrs, R.attr.SwipeBackLayoutStyle);  | 
            |
| 133 | 
                + }  | 
            |
| 134 | 
                +  | 
            |
| 135 | 
                +    public SwipeBackLayout(Context context, AttributeSet attrs, int defStyle) {
               | 
            |
| 136 | 
                + super(context, attrs);  | 
            |
| 137 | 
                + mDragHelper = ViewDragHelper.create(this, new ViewDragCallback());  | 
            |
| 138 | 
                +  | 
            |
| 139 | 
                + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwipeBackLayout, defStyle,  | 
            |
| 140 | 
                + R.style.SwipeBackLayout);  | 
            |
| 141 | 
                +  | 
            |
| 142 | 
                + int edgeSize = a.getDimensionPixelSize(R.styleable.SwipeBackLayout_edge_size, -1);  | 
            |
| 143 | 
                + if (edgeSize > 0)  | 
            |
| 144 | 
                + setEdgeSize(edgeSize);  | 
            |
| 145 | 
                + int mode = EDGE_FLAGS[a.getInt(R.styleable.SwipeBackLayout_edge_flag, 0)];  | 
            |
| 146 | 
                + setEdgeTrackingEnabled(mode);  | 
            |
| 147 | 
                +  | 
            |
| 148 | 
                + int shadowLeft = a.getResourceId(R.styleable.SwipeBackLayout_shadow_left,  | 
            |
| 149 | 
                + R.drawable.shadow_left);  | 
            |
| 150 | 
                + int shadowRight = a.getResourceId(R.styleable.SwipeBackLayout_shadow_right,  | 
            |
| 151 | 
                + R.drawable.shadow_right);  | 
            |
| 152 | 
                + int shadowBottom = a.getResourceId(R.styleable.SwipeBackLayout_shadow_bottom,  | 
            |
| 153 | 
                + R.drawable.shadow_bottom);  | 
            |
| 154 | 
                + setShadow(shadowLeft, EDGE_LEFT);  | 
            |
| 155 | 
                + setShadow(shadowRight, EDGE_RIGHT);  | 
            |
| 156 | 
                + setShadow(shadowBottom, EDGE_BOTTOM);  | 
            |
| 157 | 
                + a.recycle();  | 
            |
| 158 | 
                + final float density = getResources().getDisplayMetrics().density;  | 
            |
| 159 | 
                + final float minVel = MIN_FLING_VELOCITY * density;  | 
            |
| 160 | 
                + mDragHelper.setMinVelocity(minVel);  | 
            |
| 161 | 
                + mDragHelper.setMaxVelocity(minVel * 2f);  | 
            |
| 162 | 
                + }  | 
            |
| 163 | 
                +  | 
            |
| 164 | 
                + /**  | 
            |
| 165 | 
                + * Sets the sensitivity of the NavigationLayout.  | 
            |
| 166 | 
                + *  | 
            |
| 167 | 
                + * @param context The application context.  | 
            |
| 168 | 
                + * @param sensitivity value between 0 and 1, the final value for touchSlop =  | 
            |
| 169 | 
                + * ViewConfiguration.getScaledTouchSlop * (1 / s);  | 
            |
| 170 | 
                + */  | 
            |
| 171 | 
                +    public void setSensitivity(Context context, float sensitivity) {
               | 
            |
| 172 | 
                + mDragHelper.setSensitivity(context, sensitivity);  | 
            |
| 173 | 
                + }  | 
            |
| 174 | 
                +  | 
            |
| 175 | 
                + /**  | 
            |
| 176 | 
                + * Set up contentView which will be moved by user gesture  | 
            |
| 177 | 
                + *  | 
            |
| 178 | 
                + * @param view  | 
            |
| 179 | 
                + */  | 
            |
| 180 | 
                +    private void setContentView(View view) {
               | 
            |
| 181 | 
                + mContentView = view;  | 
            |
| 182 | 
                + }  | 
            |
| 183 | 
                +  | 
            |
| 184 | 
                +    public void setEnableGesture(boolean enable) {
               | 
            |
| 185 | 
                + mEnable = enable;  | 
            |
| 186 | 
                + }  | 
            |
| 187 | 
                +  | 
            |
| 188 | 
                + /**  | 
            |
| 189 | 
                + * Enable edge tracking for the selected edges of the parent view. The  | 
            |
| 190 | 
                + * callback's  | 
            |
| 191 | 
                + *  | 
            |
| 192 | 
                + * @param edgeFlags Combination of edge flags describing the edges to watch  | 
            |
| 193 | 
                + * @see #EDGE_LEFT  | 
            |
| 194 | 
                + * @see #EDGE_RIGHT  | 
            |
| 195 | 
                + * @see #EDGE_BOTTOM  | 
            |
| 196 | 
                + */  | 
            |
| 197 | 
                +    public void setEdgeTrackingEnabled(int edgeFlags) {
               | 
            |
| 198 | 
                + mEdgeFlag = edgeFlags;  | 
            |
| 199 | 
                + mDragHelper.setEdgeTrackingEnabled(mEdgeFlag);  | 
            |
| 200 | 
                + }  | 
            |
| 201 | 
                +  | 
            |
| 202 | 
                + /**  | 
            |
| 203 | 
                + * Set a color to use for the scrim that obscures primary content while a  | 
            |
| 204 | 
                + * drawer is open.  | 
            |
| 205 | 
                + *  | 
            |
| 206 | 
                + * @param color Color to use in 0xAARRGGBB format.  | 
            |
| 207 | 
                + */  | 
            |
| 208 | 
                +    public void setScrimColor(int color) {
               | 
            |
| 209 | 
                + mScrimColor = color;  | 
            |
| 210 | 
                + invalidate();  | 
            |
| 211 | 
                + }  | 
            |
| 212 | 
                +  | 
            |
| 213 | 
                + /**  | 
            |
| 214 | 
                + * Set the size of an edge. This is the range in pixels along the edges of  | 
            |
| 215 | 
                + * this view that will actively detect edge touches or drags if edge  | 
            |
| 216 | 
                + * tracking is enabled.  | 
            |
| 217 | 
                + *  | 
            |
| 218 | 
                + * @param size The size of an edge in pixels  | 
            |
| 219 | 
                + */  | 
            |
| 220 | 
                +    public void setEdgeSize(int size) {
               | 
            |
| 221 | 
                + mDragHelper.setEdgeSize(size);  | 
            |
| 222 | 
                + }  | 
            |
| 223 | 
                +  | 
            |
| 224 | 
                + /**  | 
            |
| 225 | 
                + * Register a callback to be invoked when a swipe event is sent to this  | 
            |
| 226 | 
                + * view.  | 
            |
| 227 | 
                + *  | 
            |
| 228 | 
                + * @param listener the swipe listener to attach to this view  | 
            |
| 229 | 
                +     * @deprecated use {@link #addSwipeListener} instead
               | 
            |
| 230 | 
                + */  | 
            |
| 231 | 
                + @Deprecated  | 
            |
| 232 | 
                +    public void setSwipeListener(SwipeListener listener) {
               | 
            |
| 233 | 
                + addSwipeListener(listener);  | 
            |
| 234 | 
                + }  | 
            |
| 235 | 
                +  | 
            |
| 236 | 
                + /**  | 
            |
| 237 | 
                + * Add a callback to be invoked when a swipe event is sent to this view.  | 
            |
| 238 | 
                + *  | 
            |
| 239 | 
                + * @param listener the swipe listener to attach to this view  | 
            |
| 240 | 
                + */  | 
            |
| 241 | 
                +    public void addSwipeListener(SwipeListener listener) {
               | 
            |
| 242 | 
                +        if (mListeners == null) {
               | 
            |
| 243 | 
                + mListeners = new ArrayList<SwipeListener>();  | 
            |
| 244 | 
                + }  | 
            |
| 245 | 
                + mListeners.add(listener);  | 
            |
| 246 | 
                + }  | 
            |
| 247 | 
                +  | 
            |
| 248 | 
                + /**  | 
            |
| 249 | 
                + * Removes a listener from the set of listeners  | 
            |
| 250 | 
                + *  | 
            |
| 251 | 
                + * @param listener  | 
            |
| 252 | 
                + */  | 
            |
| 253 | 
                +    public void removeSwipeListener(SwipeListener listener) {
               | 
            |
| 254 | 
                +        if (mListeners == null) {
               | 
            |
| 255 | 
                + return;  | 
            |
| 256 | 
                + }  | 
            |
| 257 | 
                + mListeners.remove(listener);  | 
            |
| 258 | 
                + }  | 
            |
| 259 | 
                +  | 
            |
| 260 | 
                +    public static interface SwipeListener {
               | 
            |
| 261 | 
                + /**  | 
            |
| 262 | 
                + * Invoke when state change  | 
            |
| 263 | 
                + *  | 
            |
| 264 | 
                + * @param state flag to describe scroll state  | 
            |
| 265 | 
                + * @param scrollPercent scroll percent of this view  | 
            |
| 266 | 
                + * @see #STATE_IDLE  | 
            |
| 267 | 
                + * @see #STATE_DRAGGING  | 
            |
| 268 | 
                + * @see #STATE_SETTLING  | 
            |
| 269 | 
                + */  | 
            |
| 270 | 
                + public void onScrollStateChange(int state, float scrollPercent);  | 
            |
| 271 | 
                +  | 
            |
| 272 | 
                + /**  | 
            |
| 273 | 
                + * Invoke when edge touched  | 
            |
| 274 | 
                + *  | 
            |
| 275 | 
                + * @param edgeFlag edge flag describing the edge being touched  | 
            |
| 276 | 
                + * @see #EDGE_LEFT  | 
            |
| 277 | 
                + * @see #EDGE_RIGHT  | 
            |
| 278 | 
                + * @see #EDGE_BOTTOM  | 
            |
| 279 | 
                + */  | 
            |
| 280 | 
                + public void onEdgeTouch(int edgeFlag);  | 
            |
| 281 | 
                +  | 
            |
| 282 | 
                + /**  | 
            |
| 283 | 
                + * Invoke when scroll percent over the threshold for the first time  | 
            |
| 284 | 
                + */  | 
            |
| 285 | 
                + public void onScrollOverThreshold();  | 
            |
| 286 | 
                + }  | 
            |
| 287 | 
                +  | 
            |
| 288 | 
                + /**  | 
            |
| 289 | 
                + * Set scroll threshold, we will close the activity, when scrollPercent over  | 
            |
| 290 | 
                + * this value  | 
            |
| 291 | 
                + *  | 
            |
| 292 | 
                + * @param threshold  | 
            |
| 293 | 
                + */  | 
            |
| 294 | 
                +    public void setScrollThresHold(float threshold) {
               | 
            |
| 295 | 
                +        if (threshold >= 1.0f || threshold <= 0) {
               | 
            |
| 296 | 
                +            throw new IllegalArgumentException("Threshold value should be between 0 and 1.0");
               | 
            |
| 297 | 
                + }  | 
            |
| 298 | 
                + mScrollThreshold = threshold;  | 
            |
| 299 | 
                + }  | 
            |
| 300 | 
                +  | 
            |
| 301 | 
                + /**  | 
            |
| 302 | 
                + * Set a drawable used for edge shadow.  | 
            |
| 303 | 
                + *  | 
            |
| 304 | 
                + * @param shadow Drawable to use  | 
            |
| 305 | 
                + * @param edgeFlag Combination of edge flags describing the edge to set  | 
            |
| 306 | 
                + * @see #EDGE_LEFT  | 
            |
| 307 | 
                + * @see #EDGE_RIGHT  | 
            |
| 308 | 
                + * @see #EDGE_BOTTOM  | 
            |
| 309 | 
                + */  | 
            |
| 310 | 
                +    public void setShadow(Drawable shadow, int edgeFlag) {
               | 
            |
| 311 | 
                +        if ((edgeFlag & EDGE_LEFT) != 0) {
               | 
            |
| 312 | 
                + mShadowLeft = shadow;  | 
            |
| 313 | 
                +        } else if ((edgeFlag & EDGE_RIGHT) != 0) {
               | 
            |
| 314 | 
                + mShadowRight = shadow;  | 
            |
| 315 | 
                +        } else if ((edgeFlag & EDGE_BOTTOM) != 0) {
               | 
            |
| 316 | 
                + mShadowBottom = shadow;  | 
            |
| 317 | 
                + }  | 
            |
| 318 | 
                + invalidate();  | 
            |
| 319 | 
                + }  | 
            |
| 320 | 
                +  | 
            |
| 321 | 
                + /**  | 
            |
| 322 | 
                + * Set a drawable used for edge shadow.  | 
            |
| 323 | 
                + *  | 
            |
| 324 | 
                + * @param resId Resource of drawable to use  | 
            |
| 325 | 
                + * @param edgeFlag Combination of edge flags describing the edge to set  | 
            |
| 326 | 
                + * @see #EDGE_LEFT  | 
            |
| 327 | 
                + * @see #EDGE_RIGHT  | 
            |
| 328 | 
                + * @see #EDGE_BOTTOM  | 
            |
| 329 | 
                + */  | 
            |
| 330 | 
                +    public void setShadow(int resId, int edgeFlag) {
               | 
            |
| 331 | 
                + setShadow(getResources().getDrawable(resId), edgeFlag);  | 
            |
| 332 | 
                + }  | 
            |
| 333 | 
                +  | 
            |
| 334 | 
                + /**  | 
            |
| 335 | 
                + * Scroll out contentView and finish the activity  | 
            |
| 336 | 
                + */  | 
            |
| 337 | 
                +    public void scrollToFinishActivity() {
               | 
            |
| 338 | 
                + final int childWidth = mContentView.getWidth();  | 
            |
| 339 | 
                + final int childHeight = mContentView.getHeight();  | 
            |
| 340 | 
                +  | 
            |
| 341 | 
                + int left = 0, top = 0;  | 
            |
| 342 | 
                +        if ((mEdgeFlag & EDGE_LEFT) != 0) {
               | 
            |
| 343 | 
                + left = childWidth + mShadowLeft.getIntrinsicWidth() + OVERSCROLL_DISTANCE;  | 
            |
| 344 | 
                + mTrackingEdge = EDGE_LEFT;  | 
            |
| 345 | 
                +        } else if ((mEdgeFlag & EDGE_RIGHT) != 0) {
               | 
            |
| 346 | 
                + left = -childWidth - mShadowRight.getIntrinsicWidth() - OVERSCROLL_DISTANCE;  | 
            |
| 347 | 
                + mTrackingEdge = EDGE_RIGHT;  | 
            |
| 348 | 
                +        } else if ((mEdgeFlag & EDGE_BOTTOM) != 0) {
               | 
            |
| 349 | 
                + top = -childHeight - mShadowBottom.getIntrinsicHeight() - OVERSCROLL_DISTANCE;  | 
            |
| 350 | 
                + mTrackingEdge = EDGE_BOTTOM;  | 
            |
| 351 | 
                + }  | 
            |
| 352 | 
                +  | 
            |
| 353 | 
                + mDragHelper.smoothSlideViewTo(mContentView, left, top);  | 
            |
| 354 | 
                + invalidate();  | 
            |
| 355 | 
                + }  | 
            |
| 356 | 
                +  | 
            |
| 357 | 
                + @Override  | 
            |
| 358 | 
                +    public boolean onInterceptTouchEvent(MotionEvent event) {
               | 
            |
| 359 | 
                +        if (!mEnable) {
               | 
            |
| 360 | 
                + return false;  | 
            |
| 361 | 
                + }  | 
            |
| 362 | 
                +        try {
               | 
            |
| 363 | 
                + return mDragHelper.shouldInterceptTouchEvent(event);  | 
            |
| 364 | 
                +        } catch (ArrayIndexOutOfBoundsException e) {
               | 
            |
| 365 | 
                + // FIXME: handle exception  | 
            |
| 366 | 
                + // issues #9  | 
            |
| 367 | 
                + return false;  | 
            |
| 368 | 
                + }  | 
            |
| 369 | 
                + }  | 
            |
| 370 | 
                +  | 
            |
| 371 | 
                + @Override  | 
            |
| 372 | 
                +    public boolean onTouchEvent(MotionEvent event) {
               | 
            |
| 373 | 
                +        if (!mEnable) {
               | 
            |
| 374 | 
                + return false;  | 
            |
| 375 | 
                + }  | 
            |
| 376 | 
                + mDragHelper.processTouchEvent(event);  | 
            |
| 377 | 
                + return true;  | 
            |
| 378 | 
                + }  | 
            |
| 379 | 
                +  | 
            |
| 380 | 
                + @Override  | 
            |
| 381 | 
                +    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
               | 
            |
| 382 | 
                + mInLayout = true;  | 
            |
| 383 | 
                + if (mContentView != null)  | 
            |
| 384 | 
                + mContentView.layout(mContentLeft, mContentTop,  | 
            |
| 385 | 
                + mContentLeft + mContentView.getMeasuredWidth(),  | 
            |
| 386 | 
                + mContentTop + mContentView.getMeasuredHeight());  | 
            |
| 387 | 
                + mInLayout = false;  | 
            |
| 388 | 
                + }  | 
            |
| 389 | 
                +  | 
            |
| 390 | 
                + @Override  | 
            |
| 391 | 
                +    public void requestLayout() {
               | 
            |
| 392 | 
                +        if (!mInLayout) {
               | 
            |
| 393 | 
                + super.requestLayout();  | 
            |
| 394 | 
                + }  | 
            |
| 395 | 
                + }  | 
            |
| 396 | 
                +  | 
            |
| 397 | 
                + @Override  | 
            |
| 398 | 
                +    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
               | 
            |
| 399 | 
                + final boolean drawContent = child == mContentView;  | 
            |
| 400 | 
                +  | 
            |
| 401 | 
                + boolean ret = super.drawChild(canvas, child, drawingTime);  | 
            |
| 402 | 
                + if (mScrimOpacity > 0 && drawContent  | 
            |
| 403 | 
                +                && mDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE) {
               | 
            |
| 404 | 
                + drawShadow(canvas, child);  | 
            |
| 405 | 
                + drawScrim(canvas, child);  | 
            |
| 406 | 
                + }  | 
            |
| 407 | 
                + return ret;  | 
            |
| 408 | 
                + }  | 
            |
| 409 | 
                +  | 
            |
| 410 | 
                +    private void drawScrim(Canvas canvas, View child) {
               | 
            |
| 411 | 
                + final int baseAlpha = (mScrimColor & 0xff000000) >>> 24;  | 
            |
| 412 | 
                + final int alpha = (int) (baseAlpha * mScrimOpacity);  | 
            |
| 413 | 
                + final int color = alpha << 24 | (mScrimColor & 0xffffff);  | 
            |
| 414 | 
                +  | 
            |
| 415 | 
                +        if ((mTrackingEdge & EDGE_LEFT) != 0) {
               | 
            |
| 416 | 
                + canvas.clipRect(0, 0, child.getLeft(), getHeight());  | 
            |
| 417 | 
                +        } else if ((mTrackingEdge & EDGE_RIGHT) != 0) {
               | 
            |
| 418 | 
                + canvas.clipRect(child.getRight(), 0, getRight(), getHeight());  | 
            |
| 419 | 
                +        } else if ((mTrackingEdge & EDGE_BOTTOM) != 0) {
               | 
            |
| 420 | 
                + canvas.clipRect(child.getLeft(), child.getBottom(), getRight(), getHeight());  | 
            |
| 421 | 
                + }  | 
            |
| 422 | 
                + canvas.drawColor(color);  | 
            |
| 423 | 
                + }  | 
            |
| 424 | 
                +  | 
            |
| 425 | 
                +    private void drawShadow(Canvas canvas, View child) {
               | 
            |
| 426 | 
                + final Rect childRect = mTmpRect;  | 
            |
| 427 | 
                + child.getHitRect(childRect);  | 
            |
| 428 | 
                +  | 
            |
| 429 | 
                +        if ((mEdgeFlag & EDGE_LEFT) != 0) {
               | 
            |
| 430 | 
                + mShadowLeft.setBounds(childRect.left - mShadowLeft.getIntrinsicWidth(), childRect.top,  | 
            |
| 431 | 
                + childRect.left, childRect.bottom);  | 
            |
| 432 | 
                + mShadowLeft.setAlpha((int) (mScrimOpacity * FULL_ALPHA));  | 
            |
| 433 | 
                + mShadowLeft.draw(canvas);  | 
            |
| 434 | 
                + }  | 
            |
| 435 | 
                +  | 
            |
| 436 | 
                +        if ((mEdgeFlag & EDGE_RIGHT) != 0) {
               | 
            |
| 437 | 
                + mShadowRight.setBounds(childRect.right, childRect.top,  | 
            |
| 438 | 
                + childRect.right + mShadowRight.getIntrinsicWidth(), childRect.bottom);  | 
            |
| 439 | 
                + mShadowRight.setAlpha((int) (mScrimOpacity * FULL_ALPHA));  | 
            |
| 440 | 
                + mShadowRight.draw(canvas);  | 
            |
| 441 | 
                + }  | 
            |
| 442 | 
                +  | 
            |
| 443 | 
                +        if ((mEdgeFlag & EDGE_BOTTOM) != 0) {
               | 
            |
| 444 | 
                + mShadowBottom.setBounds(childRect.left, childRect.bottom, childRect.right,  | 
            |
| 445 | 
                + childRect.bottom + mShadowBottom.getIntrinsicHeight());  | 
            |
| 446 | 
                + mShadowBottom.setAlpha((int) (mScrimOpacity * FULL_ALPHA));  | 
            |
| 447 | 
                + mShadowBottom.draw(canvas);  | 
            |
| 448 | 
                + }  | 
            |
| 449 | 
                + }  | 
            |
| 450 | 
                +  | 
            |
| 451 | 
                +    public void attachToActivity(Activity activity) {
               | 
            |
| 452 | 
                + mActivity = activity;  | 
            |
| 453 | 
                +        TypedArray a = activity.getTheme().obtainStyledAttributes(new int[]{
               | 
            |
| 454 | 
                + android.R.attr.windowBackground  | 
            |
| 455 | 
                + });  | 
            |
| 456 | 
                + int background = a.getResourceId(0, 0);  | 
            |
| 457 | 
                + a.recycle();  | 
            |
| 458 | 
                +  | 
            |
| 459 | 
                + ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView();  | 
            |
| 460 | 
                + ViewGroup decorChild = (ViewGroup) decor.getChildAt(0);  | 
            |
| 461 | 
                + decorChild.setBackgroundResource(background);  | 
            |
| 462 | 
                + decor.removeView(decorChild);  | 
            |
| 463 | 
                + addView(decorChild);  | 
            |
| 464 | 
                + setContentView(decorChild);  | 
            |
| 465 | 
                + decor.addView(this);  | 
            |
| 466 | 
                + }  | 
            |
| 467 | 
                +  | 
            |
| 468 | 
                + @Override  | 
            |
| 469 | 
                +    public void computeScroll() {
               | 
            |
| 470 | 
                + mScrimOpacity = 1 - mScrollPercent;  | 
            |
| 471 | 
                +        if (mDragHelper.continueSettling(true)) {
               | 
            |
| 472 | 
                + ViewCompat.postInvalidateOnAnimation(this);  | 
            |
| 473 | 
                + }  | 
            |
| 474 | 
                + }  | 
            |
| 475 | 
                +  | 
            |
| 476 | 
                +    private class ViewDragCallback extends ViewDragHelper.Callback {
               | 
            |
| 477 | 
                + private boolean mIsScrollOverValid;  | 
            |
| 478 | 
                +  | 
            |
| 479 | 
                + @Override  | 
            |
| 480 | 
                +        public boolean tryCaptureView(View view, int i) {
               | 
            |
| 481 | 
                + boolean ret = mDragHelper.isEdgeTouched(mEdgeFlag, i);  | 
            |
| 482 | 
                +            if (ret) {
               | 
            |
| 483 | 
                +                if (mDragHelper.isEdgeTouched(EDGE_LEFT, i)) {
               | 
            |
| 484 | 
                + mTrackingEdge = EDGE_LEFT;  | 
            |
| 485 | 
                +                } else if (mDragHelper.isEdgeTouched(EDGE_RIGHT, i)) {
               | 
            |
| 486 | 
                + mTrackingEdge = EDGE_RIGHT;  | 
            |
| 487 | 
                +                } else if (mDragHelper.isEdgeTouched(EDGE_BOTTOM, i)) {
               | 
            |
| 488 | 
                + mTrackingEdge = EDGE_BOTTOM;  | 
            |
| 489 | 
                + }  | 
            |
| 490 | 
                +                if (mListeners != null && !mListeners.isEmpty()) {
               | 
            |
| 491 | 
                +                    for (SwipeListener listener : mListeners) {
               | 
            |
| 492 | 
                + listener.onEdgeTouch(mTrackingEdge);  | 
            |
| 493 | 
                + }  | 
            |
| 494 | 
                + }  | 
            |
| 495 | 
                + mIsScrollOverValid = true;  | 
            |
| 496 | 
                + }  | 
            |
| 497 | 
                + boolean directionCheck = false;  | 
            |
| 498 | 
                +            if (mEdgeFlag == EDGE_LEFT || mEdgeFlag == EDGE_RIGHT) {
               | 
            |
| 499 | 
                + directionCheck = !mDragHelper.checkTouchSlop(ViewDragHelper.DIRECTION_VERTICAL, i);  | 
            |
| 500 | 
                +            } else if (mEdgeFlag == EDGE_BOTTOM) {
               | 
            |
| 501 | 
                + directionCheck = !mDragHelper  | 
            |
| 502 | 
                + .checkTouchSlop(ViewDragHelper.DIRECTION_HORIZONTAL, i);  | 
            |
| 503 | 
                +            } else if (mEdgeFlag == EDGE_ALL) {
               | 
            |
| 504 | 
                + directionCheck = true;  | 
            |
| 505 | 
                + }  | 
            |
| 506 | 
                + return ret & directionCheck;  | 
            |
| 507 | 
                + }  | 
            |
| 508 | 
                +  | 
            |
| 509 | 
                + @Override  | 
            |
| 510 | 
                +        public int getViewHorizontalDragRange(View child) {
               | 
            |
| 511 | 
                + return mEdgeFlag & (EDGE_LEFT | EDGE_RIGHT);  | 
            |
| 512 | 
                + }  | 
            |
| 513 | 
                +  | 
            |
| 514 | 
                + @Override  | 
            |
| 515 | 
                +        public int getViewVerticalDragRange(View child) {
               | 
            |
| 516 | 
                + return mEdgeFlag & EDGE_BOTTOM;  | 
            |
| 517 | 
                + }  | 
            |
| 518 | 
                +  | 
            |
| 519 | 
                + @Override  | 
            |
| 520 | 
                +        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
               | 
            |
| 521 | 
                + super.onViewPositionChanged(changedView, left, top, dx, dy);  | 
            |
| 522 | 
                +            if ((mTrackingEdge & EDGE_LEFT) != 0) {
               | 
            |
| 523 | 
                + mScrollPercent = Math.abs((float) left  | 
            |
| 524 | 
                + / (mContentView.getWidth() + mShadowLeft.getIntrinsicWidth()));  | 
            |
| 525 | 
                +            } else if ((mTrackingEdge & EDGE_RIGHT) != 0) {
               | 
            |
| 526 | 
                + mScrollPercent = Math.abs((float) left  | 
            |
| 527 | 
                + / (mContentView.getWidth() + mShadowRight.getIntrinsicWidth()));  | 
            |
| 528 | 
                +            } else if ((mTrackingEdge & EDGE_BOTTOM) != 0) {
               | 
            |
| 529 | 
                + mScrollPercent = Math.abs((float) top  | 
            |
| 530 | 
                + / (mContentView.getHeight() + mShadowBottom.getIntrinsicHeight()));  | 
            |
| 531 | 
                + }  | 
            |
| 532 | 
                + mContentLeft = left;  | 
            |
| 533 | 
                + mContentTop = top;  | 
            |
| 534 | 
                + invalidate();  | 
            |
| 535 | 
                +            if (mScrollPercent < mScrollThreshold && !mIsScrollOverValid) {
               | 
            |
| 536 | 
                + mIsScrollOverValid = true;  | 
            |
| 537 | 
                + }  | 
            |
| 538 | 
                + if (mListeners != null && !mListeners.isEmpty()  | 
            |
| 539 | 
                + && mDragHelper.getViewDragState() == STATE_DRAGGING  | 
            |
| 540 | 
                +                    && mScrollPercent >= mScrollThreshold && mIsScrollOverValid) {
               | 
            |
| 541 | 
                + mIsScrollOverValid = false;  | 
            |
| 542 | 
                +                for (SwipeListener listener : mListeners) {
               | 
            |
| 543 | 
                + listener.onScrollOverThreshold();  | 
            |
| 544 | 
                + }  | 
            |
| 545 | 
                + }  | 
            |
| 546 | 
                +  | 
            |
| 547 | 
                +            if (mScrollPercent >= 1) {
               | 
            |
| 548 | 
                +                if (!mActivity.isFinishing()) {
               | 
            |
| 549 | 
                + mActivity.finish();  | 
            |
| 550 | 
                + mActivity.overridePendingTransition(0, 0);  | 
            |
| 551 | 
                + }  | 
            |
| 552 | 
                + }  | 
            |
| 553 | 
                + }  | 
            |
| 554 | 
                +  | 
            |
| 555 | 
                + @Override  | 
            |
| 556 | 
                +        public void onViewReleased(View releasedChild, float xvel, float yvel) {
               | 
            |
| 557 | 
                + final int childWidth = releasedChild.getWidth();  | 
            |
| 558 | 
                + final int childHeight = releasedChild.getHeight();  | 
            |
| 559 | 
                +  | 
            |
| 560 | 
                + int left = 0, top = 0;  | 
            |
| 561 | 
                +            if ((mTrackingEdge & EDGE_LEFT) != 0) {
               | 
            |
| 562 | 
                + left = xvel > 0 || xvel == 0 && mScrollPercent > mScrollThreshold ? childWidth  | 
            |
| 563 | 
                + + mShadowLeft.getIntrinsicWidth() + OVERSCROLL_DISTANCE : 0;  | 
            |
| 564 | 
                +            } else if ((mTrackingEdge & EDGE_RIGHT) != 0) {
               | 
            |
| 565 | 
                + left = xvel < 0 || xvel == 0 && mScrollPercent > mScrollThreshold ? -(childWidth  | 
            |
| 566 | 
                + + mShadowLeft.getIntrinsicWidth() + OVERSCROLL_DISTANCE) : 0;  | 
            |
| 567 | 
                +            } else if ((mTrackingEdge & EDGE_BOTTOM) != 0) {
               | 
            |
| 568 | 
                + top = yvel < 0 || yvel == 0 && mScrollPercent > mScrollThreshold ? -(childHeight  | 
            |
| 569 | 
                + + mShadowBottom.getIntrinsicHeight() + OVERSCROLL_DISTANCE) : 0;  | 
            |
| 570 | 
                + }  | 
            |
| 571 | 
                +  | 
            |
| 572 | 
                + mDragHelper.settleCapturedViewAt(left, top);  | 
            |
| 573 | 
                + invalidate();  | 
            |
| 574 | 
                + }  | 
            |
| 575 | 
                +  | 
            |
| 576 | 
                + @Override  | 
            |
| 577 | 
                +        public int clampViewPositionHorizontal(View child, int left, int dx) {
               | 
            |
| 578 | 
                + int ret = 0;  | 
            |
| 579 | 
                +            if ((mTrackingEdge & EDGE_LEFT) != 0) {
               | 
            |
| 580 | 
                + ret = Math.min(child.getWidth(), Math.max(left, 0));  | 
            |
| 581 | 
                +            } else if ((mTrackingEdge & EDGE_RIGHT) != 0) {
               | 
            |
| 582 | 
                + ret = Math.min(0, Math.max(left, -child.getWidth()));  | 
            |
| 583 | 
                + }  | 
            |
| 584 | 
                + return ret;  | 
            |
| 585 | 
                + }  | 
            |
| 586 | 
                +  | 
            |
| 587 | 
                + @Override  | 
            |
| 588 | 
                +        public int clampViewPositionVertical(View child, int top, int dy) {
               | 
            |
| 589 | 
                + int ret = 0;  | 
            |
| 590 | 
                +            if ((mTrackingEdge & EDGE_BOTTOM) != 0) {
               | 
            |
| 591 | 
                + ret = Math.min(0, Math.max(top, -child.getHeight()));  | 
            |
| 592 | 
                + }  | 
            |
| 593 | 
                + return ret;  | 
            |
| 594 | 
                + }  | 
            |
| 595 | 
                +  | 
            |
| 596 | 
                + @Override  | 
            |
| 597 | 
                +        public void onViewDragStateChanged(int state) {
               | 
            |
| 598 | 
                + super.onViewDragStateChanged(state);  | 
            |
| 599 | 
                +            if (mListeners != null && !mListeners.isEmpty()) {
               | 
            |
| 600 | 
                +                for (SwipeListener listener : mListeners) {
               | 
            |
| 601 | 
                + listener.onScrollStateChange(state, mScrollPercent);  | 
            |
| 602 | 
                + }  | 
            |
| 603 | 
                + }  | 
            |
| 604 | 
                + }  | 
            |
| 605 | 
                + }  | 
            |
| 606 | 
                +}  | 
            
                @@ -0,0 +1,103 @@  | 
            ||
| 1 | 
                +  | 
            |
| 2 | 
                +package com.android.views.swipebacklayout;  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +import android.app.Activity;  | 
            |
| 5 | 
                +import android.app.ActivityOptions;  | 
            |
| 6 | 
                +import android.os.Build;  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +import java.lang.reflect.Method;  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                +/**  | 
            |
| 11 | 
                + * Created by Chaojun Wang on 6/9/14.  | 
            |
| 12 | 
                + */  | 
            |
| 13 | 
                +public class Utils {
               | 
            |
| 14 | 
                +    private Utils() {
               | 
            |
| 15 | 
                + }  | 
            |
| 16 | 
                +  | 
            |
| 17 | 
                + /**  | 
            |
| 18 | 
                + * Convert a translucent themed Activity  | 
            |
| 19 | 
                +     * {@link android.R.attr#windowIsTranslucent} to a fullscreen opaque
               | 
            |
| 20 | 
                + * Activity.  | 
            |
| 21 | 
                + * <p>  | 
            |
| 22 | 
                + * Call this whenever the background of a translucent Activity has changed  | 
            |
| 23 | 
                +     * to become opaque. Doing so will allow the {@link android.view.Surface} of
               | 
            |
| 24 | 
                + * the Activity behind to be released.  | 
            |
| 25 | 
                + * <p>  | 
            |
| 26 | 
                + * This call has no effect on non-translucent activities or on activities  | 
            |
| 27 | 
                +     * with the {@link android.R.attr#windowIsFloating} attribute.
               | 
            |
| 28 | 
                + */  | 
            |
| 29 | 
                +    public static void convertActivityFromTranslucent(Activity activity) {
               | 
            |
| 30 | 
                +        try {
               | 
            |
| 31 | 
                +            Method method = Activity.class.getDeclaredMethod("convertFromTranslucent");
               | 
            |
| 32 | 
                + method.setAccessible(true);  | 
            |
| 33 | 
                + method.invoke(activity);  | 
            |
| 34 | 
                +        } catch (Throwable t) {
               | 
            |
| 35 | 
                + }  | 
            |
| 36 | 
                + }  | 
            |
| 37 | 
                +  | 
            |
| 38 | 
                + /**  | 
            |
| 39 | 
                + * Convert a translucent themed Activity  | 
            |
| 40 | 
                +     * {@link android.R.attr#windowIsTranslucent} back from opaque to
               | 
            |
| 41 | 
                + * translucent following a call to  | 
            |
| 42 | 
                +     * {@link #convertActivityFromTranslucent(Activity)} .
               | 
            |
| 43 | 
                + * <p>  | 
            |
| 44 | 
                + * Calling this allows the Activity behind this one to be seen again. Once  | 
            |
| 45 | 
                + * all such Activities have been redrawn  | 
            |
| 46 | 
                + * <p>  | 
            |
| 47 | 
                + * This call has no effect on non-translucent activities or on activities  | 
            |
| 48 | 
                +     * with the {@link android.R.attr#windowIsFloating} attribute.
               | 
            |
| 49 | 
                + */  | 
            |
| 50 | 
                +    public static void convertActivityToTranslucent(Activity activity) {
               | 
            |
| 51 | 
                +        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
               | 
            |
| 52 | 
                + convertActivityToTranslucentAfterL(activity);  | 
            |
| 53 | 
                +        } else {
               | 
            |
| 54 | 
                + convertActivityToTranslucentBeforeL(activity);  | 
            |
| 55 | 
                + }  | 
            |
| 56 | 
                + }  | 
            |
| 57 | 
                +  | 
            |
| 58 | 
                + /**  | 
            |
| 59 | 
                + * Calling the convertToTranslucent method on platforms before Android 5.0  | 
            |
| 60 | 
                + */  | 
            |
| 61 | 
                +    public static void convertActivityToTranslucentBeforeL(Activity activity) {
               | 
            |
| 62 | 
                +        try {
               | 
            |
| 63 | 
                + Class<?>[] classes = Activity.class.getDeclaredClasses();  | 
            |
| 64 | 
                + Class<?> translucentConversionListenerClazz = null;  | 
            |
| 65 | 
                +            for (Class clazz : classes) {
               | 
            |
| 66 | 
                +                if (clazz.getSimpleName().contains("TranslucentConversionListener")) {
               | 
            |
| 67 | 
                + translucentConversionListenerClazz = clazz;  | 
            |
| 68 | 
                + }  | 
            |
| 69 | 
                + }  | 
            |
| 70 | 
                +            Method method = Activity.class.getDeclaredMethod("convertToTranslucent",
               | 
            |
| 71 | 
                + translucentConversionListenerClazz);  | 
            |
| 72 | 
                + method.setAccessible(true);  | 
            |
| 73 | 
                +            method.invoke(activity, new Object[] {
               | 
            |
| 74 | 
                + null  | 
            |
| 75 | 
                + });  | 
            |
| 76 | 
                +        } catch (Throwable t) {
               | 
            |
| 77 | 
                + }  | 
            |
| 78 | 
                + }  | 
            |
| 79 | 
                +  | 
            |
| 80 | 
                + /**  | 
            |
| 81 | 
                + * Calling the convertToTranslucent method on platforms after Android 5.0  | 
            |
| 82 | 
                + */  | 
            |
| 83 | 
                +    private static void convertActivityToTranslucentAfterL(Activity activity) {
               | 
            |
| 84 | 
                +        try {
               | 
            |
| 85 | 
                +            Method getActivityOptions = Activity.class.getDeclaredMethod("getActivityOptions");
               | 
            |
| 86 | 
                + getActivityOptions.setAccessible(true);  | 
            |
| 87 | 
                + Object options = getActivityOptions.invoke(activity);  | 
            |
| 88 | 
                +  | 
            |
| 89 | 
                + Class<?>[] classes = Activity.class.getDeclaredClasses();  | 
            |
| 90 | 
                + Class<?> translucentConversionListenerClazz = null;  | 
            |
| 91 | 
                +            for (Class clazz : classes) {
               | 
            |
| 92 | 
                +                if (clazz.getSimpleName().contains("TranslucentConversionListener")) {
               | 
            |
| 93 | 
                + translucentConversionListenerClazz = clazz;  | 
            |
| 94 | 
                + }  | 
            |
| 95 | 
                + }  | 
            |
| 96 | 
                +            Method convertToTranslucent = Activity.class.getDeclaredMethod("convertToTranslucent",
               | 
            |
| 97 | 
                + translucentConversionListenerClazz, ActivityOptions.class);  | 
            |
| 98 | 
                + convertToTranslucent.setAccessible(true);  | 
            |
| 99 | 
                + convertToTranslucent.invoke(activity, null, options);  | 
            |
| 100 | 
                +        } catch (Throwable t) {
               | 
            |
| 101 | 
                + }  | 
            |
| 102 | 
                + }  | 
            |
| 103 | 
                +}  | 
            
                @@ -0,0 +1,1580 @@  | 
            ||
| 1 | 
                +/*  | 
            |
| 2 | 
                + * Copyright (C) 2013 The Android Open Source Project  | 
            |
| 3 | 
                + *  | 
            |
| 4 | 
                + * Licensed under the Apache License, Version 2.0 (the "License");  | 
            |
| 5 | 
                + * you may not use this file except in compliance with the License.  | 
            |
| 6 | 
                + * You may obtain a copy of the License at  | 
            |
| 7 | 
                + *  | 
            |
| 8 | 
                + * http://www.apache.org/licenses/LICENSE-2.0  | 
            |
| 9 | 
                + *  | 
            |
| 10 | 
                + * Unless required by applicable law or agreed to in writing, software  | 
            |
| 11 | 
                + * distributed under the License is distributed on an "AS IS" BASIS,  | 
            |
| 12 | 
                + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  | 
            |
| 13 | 
                + * See the License for the specific language governing permissions and  | 
            |
| 14 | 
                + * limitations under the License.  | 
            |
| 15 | 
                + */  | 
            |
| 16 | 
                +  | 
            |
| 17 | 
                +package com.android.views.swipebacklayout;  | 
            |
| 18 | 
                +  | 
            |
| 19 | 
                +import android.content.Context;  | 
            |
| 20 | 
                +import android.support.v4.view.MotionEventCompat;  | 
            |
| 21 | 
                +import android.support.v4.view.VelocityTrackerCompat;  | 
            |
| 22 | 
                +import android.support.v4.view.ViewCompat;  | 
            |
| 23 | 
                +import android.support.v4.widget.ScrollerCompat;  | 
            |
| 24 | 
                +import android.view.MotionEvent;  | 
            |
| 25 | 
                +import android.view.VelocityTracker;  | 
            |
| 26 | 
                +import android.view.View;  | 
            |
| 27 | 
                +import android.view.ViewConfiguration;  | 
            |
| 28 | 
                +import android.view.ViewGroup;  | 
            |
| 29 | 
                +import android.view.animation.Interpolator;  | 
            |
| 30 | 
                +  | 
            |
| 31 | 
                +import java.util.Arrays;  | 
            |
| 32 | 
                +  | 
            |
| 33 | 
                +/**  | 
            |
| 34 | 
                + * ViewDragHelper is a utility class for writing custom ViewGroups. It offers a  | 
            |
| 35 | 
                + * number of useful operations and state tracking for allowing a user to drag  | 
            |
| 36 | 
                + * and reposition views within their parent ViewGroup.  | 
            |
| 37 | 
                + */  | 
            |
| 38 | 
                +public class ViewDragHelper {
               | 
            |
| 39 | 
                + private static final String TAG = "ViewDragHelper";  | 
            |
| 40 | 
                +  | 
            |
| 41 | 
                + /**  | 
            |
| 42 | 
                + * A null/invalid pointer ID.  | 
            |
| 43 | 
                + */  | 
            |
| 44 | 
                + public static final int INVALID_POINTER = -1;  | 
            |
| 45 | 
                +  | 
            |
| 46 | 
                + /**  | 
            |
| 47 | 
                + * A view is not currently being dragged or animating as a result of a  | 
            |
| 48 | 
                + * fling/snap.  | 
            |
| 49 | 
                + */  | 
            |
| 50 | 
                + public static final int STATE_IDLE = 0;  | 
            |
| 51 | 
                +  | 
            |
| 52 | 
                + /**  | 
            |
| 53 | 
                + * A view is currently being dragged. The position is currently changing as  | 
            |
| 54 | 
                + * a result of user input or simulated user input.  | 
            |
| 55 | 
                + */  | 
            |
| 56 | 
                + public static final int STATE_DRAGGING = 1;  | 
            |
| 57 | 
                +  | 
            |
| 58 | 
                + /**  | 
            |
| 59 | 
                + * A view is currently settling into place as a result of a fling or  | 
            |
| 60 | 
                + * predefined non-interactive motion.  | 
            |
| 61 | 
                + */  | 
            |
| 62 | 
                + public static final int STATE_SETTLING = 2;  | 
            |
| 63 | 
                +  | 
            |
| 64 | 
                + /**  | 
            |
| 65 | 
                + * Edge flag indicating that the left edge should be affected.  | 
            |
| 66 | 
                + */  | 
            |
| 67 | 
                + public static final int EDGE_LEFT = 1 << 0;  | 
            |
| 68 | 
                +  | 
            |
| 69 | 
                + /**  | 
            |
| 70 | 
                + * Edge flag indicating that the right edge should be affected.  | 
            |
| 71 | 
                + */  | 
            |
| 72 | 
                + public static final int EDGE_RIGHT = 1 << 1;  | 
            |
| 73 | 
                +  | 
            |
| 74 | 
                + /**  | 
            |
| 75 | 
                + * Edge flag indicating that the top edge should be affected.  | 
            |
| 76 | 
                + */  | 
            |
| 77 | 
                + public static final int EDGE_TOP = 1 << 2;  | 
            |
| 78 | 
                +  | 
            |
| 79 | 
                + /**  | 
            |
| 80 | 
                + * Edge flag indicating that the bottom edge should be affected.  | 
            |
| 81 | 
                + */  | 
            |
| 82 | 
                + public static final int EDGE_BOTTOM = 1 << 3;  | 
            |
| 83 | 
                +  | 
            |
| 84 | 
                + /**  | 
            |
| 85 | 
                + * Edge flag set indicating all edges should be affected.  | 
            |
| 86 | 
                + */  | 
            |
| 87 | 
                + public static final int EDGE_ALL = EDGE_LEFT | EDGE_TOP | EDGE_RIGHT | EDGE_BOTTOM;  | 
            |
| 88 | 
                +  | 
            |
| 89 | 
                + /**  | 
            |
| 90 | 
                + * Indicates that a check should occur along the horizontal axis  | 
            |
| 91 | 
                + */  | 
            |
| 92 | 
                + public static final int DIRECTION_HORIZONTAL = 1 << 0;  | 
            |
| 93 | 
                +  | 
            |
| 94 | 
                + /**  | 
            |
| 95 | 
                + * Indicates that a check should occur along the vertical axis  | 
            |
| 96 | 
                + */  | 
            |
| 97 | 
                + public static final int DIRECTION_VERTICAL = 1 << 1;  | 
            |
| 98 | 
                +  | 
            |
| 99 | 
                + /**  | 
            |
| 100 | 
                + * Indicates that a check should occur along all axes  | 
            |
| 101 | 
                + */  | 
            |
| 102 | 
                + public static final int DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;  | 
            |
| 103 | 
                +  | 
            |
| 104 | 
                + public static final int EDGE_SIZE = 20; // dp  | 
            |
| 105 | 
                +  | 
            |
| 106 | 
                + private static final int BASE_SETTLE_DURATION = 256; // ms  | 
            |
| 107 | 
                +  | 
            |
| 108 | 
                + private static final int MAX_SETTLE_DURATION = 600; // ms  | 
            |
| 109 | 
                +  | 
            |
| 110 | 
                + // Current drag state; idle, dragging or settling  | 
            |
| 111 | 
                + private int mDragState;  | 
            |
| 112 | 
                +  | 
            |
| 113 | 
                + // Distance to travel before a drag may begin  | 
            |
| 114 | 
                + private int mTouchSlop;  | 
            |
| 115 | 
                +  | 
            |
| 116 | 
                + // Last known position/pointer tracking  | 
            |
| 117 | 
                + private int mActivePointerId = INVALID_POINTER;  | 
            |
| 118 | 
                +  | 
            |
| 119 | 
                + private float[] mInitialMotionX;  | 
            |
| 120 | 
                +  | 
            |
| 121 | 
                + private float[] mInitialMotionY;  | 
            |
| 122 | 
                +  | 
            |
| 123 | 
                + private float[] mLastMotionX;  | 
            |
| 124 | 
                +  | 
            |
| 125 | 
                + private float[] mLastMotionY;  | 
            |
| 126 | 
                +  | 
            |
| 127 | 
                + private int[] mInitialEdgeTouched;  | 
            |
| 128 | 
                +  | 
            |
| 129 | 
                + private int[] mEdgeDragsInProgress;  | 
            |
| 130 | 
                +  | 
            |
| 131 | 
                + private int[] mEdgeDragsLocked;  | 
            |
| 132 | 
                +  | 
            |
| 133 | 
                + private int mPointersDown;  | 
            |
| 134 | 
                +  | 
            |
| 135 | 
                + private VelocityTracker mVelocityTracker;  | 
            |
| 136 | 
                +  | 
            |
| 137 | 
                + private float mMaxVelocity;  | 
            |
| 138 | 
                +  | 
            |
| 139 | 
                + private float mMinVelocity;  | 
            |
| 140 | 
                +  | 
            |
| 141 | 
                + private int mEdgeSize;  | 
            |
| 142 | 
                +  | 
            |
| 143 | 
                + private int mTrackingEdges;  | 
            |
| 144 | 
                +  | 
            |
| 145 | 
                + private ScrollerCompat mScroller;  | 
            |
| 146 | 
                +  | 
            |
| 147 | 
                + private final Callback mCallback;  | 
            |
| 148 | 
                +  | 
            |
| 149 | 
                + private View mCapturedView;  | 
            |
| 150 | 
                +  | 
            |
| 151 | 
                + private boolean mReleaseInProgress;  | 
            |
| 152 | 
                +  | 
            |
| 153 | 
                + private final ViewGroup mParentView;  | 
            |
| 154 | 
                +  | 
            |
| 155 | 
                + /**  | 
            |
| 156 | 
                + * A Callback is used as a communication channel with the ViewDragHelper  | 
            |
| 157 | 
                + * back to the parent view using it. <code>on*</code>methods are invoked on  | 
            |
| 158 | 
                + * siginficant events and several accessor methods are expected to provide  | 
            |
| 159 | 
                + * the ViewDragHelper with more information about the state of the parent  | 
            |
| 160 | 
                + * view upon request. The callback also makes decisions governing the range  | 
            |
| 161 | 
                + * and draggability of child views.  | 
            |
| 162 | 
                + */  | 
            |
| 163 | 
                +    public static abstract class Callback {
               | 
            |
| 164 | 
                + /**  | 
            |
| 165 | 
                + * Called when the drag state changes. See the <code>STATE_*</code>  | 
            |
| 166 | 
                + * constants for more information.  | 
            |
| 167 | 
                + *  | 
            |
| 168 | 
                + * @param state The new drag state  | 
            |
| 169 | 
                + * @see #STATE_IDLE  | 
            |
| 170 | 
                + * @see #STATE_DRAGGING  | 
            |
| 171 | 
                + * @see #STATE_SETTLING  | 
            |
| 172 | 
                + */  | 
            |
| 173 | 
                +        public void onViewDragStateChanged(int state) {
               | 
            |
| 174 | 
                + }  | 
            |
| 175 | 
                +  | 
            |
| 176 | 
                + /**  | 
            |
| 177 | 
                + * Called when the captured view's position changes as the result of a  | 
            |
| 178 | 
                + * drag or settle.  | 
            |
| 179 | 
                + *  | 
            |
| 180 | 
                + * @param changedView View whose position changed  | 
            |
| 181 | 
                + * @param left New X coordinate of the left edge of the view  | 
            |
| 182 | 
                + * @param top New Y coordinate of the top edge of the view  | 
            |
| 183 | 
                + * @param dx Change in X position from the last call  | 
            |
| 184 | 
                + * @param dy Change in Y position from the last call  | 
            |
| 185 | 
                + */  | 
            |
| 186 | 
                +        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
               | 
            |
| 187 | 
                + }  | 
            |
| 188 | 
                +  | 
            |
| 189 | 
                + /**  | 
            |
| 190 | 
                + * Called when a child view is captured for dragging or settling. The ID  | 
            |
| 191 | 
                + * of the pointer currently dragging the captured view is supplied. If  | 
            |
| 192 | 
                +         * activePointerId is identified as {@link #INVALID_POINTER} the capture
               | 
            |
| 193 | 
                + * is programmatic instead of pointer-initiated.  | 
            |
| 194 | 
                + *  | 
            |
| 195 | 
                + * @param capturedChild Child view that was captured  | 
            |
| 196 | 
                + * @param activePointerId Pointer id tracking the child capture  | 
            |
| 197 | 
                + */  | 
            |
| 198 | 
                +        public void onViewCaptured(View capturedChild, int activePointerId) {
               | 
            |
| 199 | 
                + }  | 
            |
| 200 | 
                +  | 
            |
| 201 | 
                + /**  | 
            |
| 202 | 
                + * Called when the child view is no longer being actively dragged. The  | 
            |
| 203 | 
                + * fling velocity is also supplied, if relevant. The velocity values may  | 
            |
| 204 | 
                + * be clamped to system minimums or maximums.  | 
            |
| 205 | 
                + * <p>  | 
            |
| 206 | 
                + * Calling code may decide to fling or otherwise release the view to let  | 
            |
| 207 | 
                + * it settle into place. It should do so using  | 
            |
| 208 | 
                +         * {@link #settleCapturedViewAt(int, int)} or
               | 
            |
| 209 | 
                +         * {@link #flingCapturedView(int, int, int, int)}. If the Callback
               | 
            |
| 210 | 
                + * invokes one of these methods, the ViewDragHelper will enter  | 
            |
| 211 | 
                +         * {@link #STATE_SETTLING} and the view capture will not fully end until
               | 
            |
| 212 | 
                + * it comes to a complete stop. If neither of these methods is invoked  | 
            |
| 213 | 
                + * before <code>onViewReleased</code> returns, the view will stop in  | 
            |
| 214 | 
                +         * place and the ViewDragHelper will return to {@link #STATE_IDLE}.
               | 
            |
| 215 | 
                + * </p>  | 
            |
| 216 | 
                + *  | 
            |
| 217 | 
                + * @param releasedChild The captured child view now being released  | 
            |
| 218 | 
                + * @param xvel X velocity of the pointer as it left the screen in pixels  | 
            |
| 219 | 
                + * per second.  | 
            |
| 220 | 
                + * @param yvel Y velocity of the pointer as it left the screen in pixels  | 
            |
| 221 | 
                + * per second.  | 
            |
| 222 | 
                + */  | 
            |
| 223 | 
                +        public void onViewReleased(View releasedChild, float xvel, float yvel) {
               | 
            |
| 224 | 
                + }  | 
            |
| 225 | 
                +  | 
            |
| 226 | 
                + /**  | 
            |
| 227 | 
                + * Called when one of the subscribed edges in the parent view has been  | 
            |
| 228 | 
                + * touched by the user while no child view is currently captured.  | 
            |
| 229 | 
                + *  | 
            |
| 230 | 
                + * @param edgeFlags A combination of edge flags describing the edge(s)  | 
            |
| 231 | 
                + * currently touched  | 
            |
| 232 | 
                + * @param pointerId ID of the pointer touching the described edge(s)  | 
            |
| 233 | 
                + * @see #EDGE_LEFT  | 
            |
| 234 | 
                + * @see #EDGE_TOP  | 
            |
| 235 | 
                + * @see #EDGE_RIGHT  | 
            |
| 236 | 
                + * @see #EDGE_BOTTOM  | 
            |
| 237 | 
                + */  | 
            |
| 238 | 
                +        public void onEdgeTouched(int edgeFlags, int pointerId) {
               | 
            |
| 239 | 
                + }  | 
            |
| 240 | 
                +  | 
            |
| 241 | 
                + /**  | 
            |
| 242 | 
                + * Called when the given edge may become locked. This can happen if an  | 
            |
| 243 | 
                + * edge drag was preliminarily rejected before beginning, but after  | 
            |
| 244 | 
                +         * {@link #onEdgeTouched(int, int)} was called. This method should
               | 
            |
| 245 | 
                + * return true to lock this edge or false to leave it unlocked. The  | 
            |
| 246 | 
                + * default behavior is to leave edges unlocked.  | 
            |
| 247 | 
                + *  | 
            |
| 248 | 
                + * @param edgeFlags A combination of edge flags describing the edge(s)  | 
            |
| 249 | 
                + * locked  | 
            |
| 250 | 
                + * @return true to lock the edge, false to leave it unlocked  | 
            |
| 251 | 
                + */  | 
            |
| 252 | 
                +        public boolean onEdgeLock(int edgeFlags) {
               | 
            |
| 253 | 
                + return false;  | 
            |
| 254 | 
                + }  | 
            |
| 255 | 
                +  | 
            |
| 256 | 
                + /**  | 
            |
| 257 | 
                + * Called when the user has started a deliberate drag away from one of  | 
            |
| 258 | 
                + * the subscribed edges in the parent view while no child view is  | 
            |
| 259 | 
                + * currently captured.  | 
            |
| 260 | 
                + *  | 
            |
| 261 | 
                + * @param edgeFlags A combination of edge flags describing the edge(s)  | 
            |
| 262 | 
                + * dragged  | 
            |
| 263 | 
                + * @param pointerId ID of the pointer touching the described edge(s)  | 
            |
| 264 | 
                + * @see #EDGE_LEFT  | 
            |
| 265 | 
                + * @see #EDGE_TOP  | 
            |
| 266 | 
                + * @see #EDGE_RIGHT  | 
            |
| 267 | 
                + * @see #EDGE_BOTTOM  | 
            |
| 268 | 
                + */  | 
            |
| 269 | 
                +        public void onEdgeDragStarted(int edgeFlags, int pointerId) {
               | 
            |
| 270 | 
                + }  | 
            |
| 271 | 
                +  | 
            |
| 272 | 
                + /**  | 
            |
| 273 | 
                + * Called to determine the Z-order of child views.  | 
            |
| 274 | 
                + *  | 
            |
| 275 | 
                + * @param index the ordered position to query for  | 
            |
| 276 | 
                + * @return index of the view that should be ordered at position  | 
            |
| 277 | 
                + * <code>index</code>  | 
            |
| 278 | 
                + */  | 
            |
| 279 | 
                +        public int getOrderedChildIndex(int index) {
               | 
            |
| 280 | 
                + return index;  | 
            |
| 281 | 
                + }  | 
            |
| 282 | 
                +  | 
            |
| 283 | 
                + /**  | 
            |
| 284 | 
                + * Return the magnitude of a draggable child view's horizontal range of  | 
            |
| 285 | 
                + * motion in pixels. This method should return 0 for views that cannot  | 
            |
| 286 | 
                + * move horizontally.  | 
            |
| 287 | 
                + *  | 
            |
| 288 | 
                + * @param child Child view to check  | 
            |
| 289 | 
                + * @return range of horizontal motion in pixels  | 
            |
| 290 | 
                + */  | 
            |
| 291 | 
                +        public int getViewHorizontalDragRange(View child) {
               | 
            |
| 292 | 
                + return 0;  | 
            |
| 293 | 
                + }  | 
            |
| 294 | 
                +  | 
            |
| 295 | 
                + /**  | 
            |
| 296 | 
                + * Return the magnitude of a draggable child view's vertical range of  | 
            |
| 297 | 
                + * motion in pixels. This method should return 0 for views that cannot  | 
            |
| 298 | 
                + * move vertically.  | 
            |
| 299 | 
                + *  | 
            |
| 300 | 
                + * @param child Child view to check  | 
            |
| 301 | 
                + * @return range of vertical motion in pixels  | 
            |
| 302 | 
                + */  | 
            |
| 303 | 
                +        public int getViewVerticalDragRange(View child) {
               | 
            |
| 304 | 
                + return 0;  | 
            |
| 305 | 
                + }  | 
            |
| 306 | 
                +  | 
            |
| 307 | 
                + /**  | 
            |
| 308 | 
                + * Called when the user's input indicates that they want to capture the  | 
            |
| 309 | 
                + * given child view with the pointer indicated by pointerId. The  | 
            |
| 310 | 
                + * callback should return true if the user is permitted to drag the  | 
            |
| 311 | 
                + * given view with the indicated pointer.  | 
            |
| 312 | 
                + * <p>  | 
            |
| 313 | 
                + * ViewDragHelper may call this method multiple times for the same view  | 
            |
| 314 | 
                + * even if the view is already captured; this indicates that a new  | 
            |
| 315 | 
                + * pointer is trying to take control of the view.  | 
            |
| 316 | 
                + * </p>  | 
            |
| 317 | 
                + * <p>  | 
            |
| 318 | 
                + * If this method returns true, a call to  | 
            |
| 319 | 
                +         * {@link #onViewCaptured(View, int)} will follow if the
               | 
            |
| 320 | 
                + * capture is successful.  | 
            |
| 321 | 
                + * </p>  | 
            |
| 322 | 
                + *  | 
            |
| 323 | 
                + * @param child Child the user is attempting to capture  | 
            |
| 324 | 
                + * @param pointerId ID of the pointer attempting the capture  | 
            |
| 325 | 
                + * @return true if capture should be allowed, false otherwise  | 
            |
| 326 | 
                + */  | 
            |
| 327 | 
                + public abstract boolean tryCaptureView(View child, int pointerId);  | 
            |
| 328 | 
                +  | 
            |
| 329 | 
                + /**  | 
            |
| 330 | 
                + * Restrict the motion of the dragged child view along the horizontal  | 
            |
| 331 | 
                + * axis. The default implementation does not allow horizontal motion;  | 
            |
| 332 | 
                + * the extending class must override this method and provide the desired  | 
            |
| 333 | 
                + * clamping.  | 
            |
| 334 | 
                + *  | 
            |
| 335 | 
                + * @param child Child view being dragged  | 
            |
| 336 | 
                + * @param left Attempted motion along the X axis  | 
            |
| 337 | 
                + * @param dx Proposed change in position for left  | 
            |
| 338 | 
                + * @return The new clamped position for left  | 
            |
| 339 | 
                + */  | 
            |
| 340 | 
                +        public int clampViewPositionHorizontal(View child, int left, int dx) {
               | 
            |
| 341 | 
                + return 0;  | 
            |
| 342 | 
                + }  | 
            |
| 343 | 
                +  | 
            |
| 344 | 
                + /**  | 
            |
| 345 | 
                + * Restrict the motion of the dragged child view along the vertical  | 
            |
| 346 | 
                + * axis. The default implementation does not allow vertical motion; the  | 
            |
| 347 | 
                + * extending class must override this method and provide the desired  | 
            |
| 348 | 
                + * clamping.  | 
            |
| 349 | 
                + *  | 
            |
| 350 | 
                + * @param child Child view being dragged  | 
            |
| 351 | 
                + * @param top Attempted motion along the Y axis  | 
            |
| 352 | 
                + * @param dy Proposed change in position for top  | 
            |
| 353 | 
                + * @return The new clamped position for top  | 
            |
| 354 | 
                + */  | 
            |
| 355 | 
                +        public int clampViewPositionVertical(View child, int top, int dy) {
               | 
            |
| 356 | 
                + return 0;  | 
            |
| 357 | 
                + }  | 
            |
| 358 | 
                + }  | 
            |
| 359 | 
                +  | 
            |
| 360 | 
                + /**  | 
            |
| 361 | 
                + * Interpolator defining the animation curve for mScroller  | 
            |
| 362 | 
                + */  | 
            |
| 363 | 
                +    private static final Interpolator sInterpolator = new Interpolator() {
               | 
            |
| 364 | 
                +        public float getInterpolation(float t) {
               | 
            |
| 365 | 
                + t -= 1.0f;  | 
            |
| 366 | 
                + return t * t * t * t * t + 1.0f;  | 
            |
| 367 | 
                + }  | 
            |
| 368 | 
                + };  | 
            |
| 369 | 
                +  | 
            |
| 370 | 
                +    private final Runnable mSetIdleRunnable = new Runnable() {
               | 
            |
| 371 | 
                +        public void run() {
               | 
            |
| 372 | 
                + setDragState(STATE_IDLE);  | 
            |
| 373 | 
                + }  | 
            |
| 374 | 
                + };  | 
            |
| 375 | 
                +  | 
            |
| 376 | 
                + /**  | 
            |
| 377 | 
                + * Factory method to create a new ViewDragHelper.  | 
            |
| 378 | 
                + *  | 
            |
| 379 | 
                + * @param forParent Parent view to monitor  | 
            |
| 380 | 
                + * @param cb Callback to provide information and receive events  | 
            |
| 381 | 
                + * @return a new ViewDragHelper instance  | 
            |
| 382 | 
                + */  | 
            |
| 383 | 
                +    public static ViewDragHelper create(ViewGroup forParent, Callback cb) {
               | 
            |
| 384 | 
                + return new ViewDragHelper(forParent.getContext(), forParent, cb);  | 
            |
| 385 | 
                + }  | 
            |
| 386 | 
                +  | 
            |
| 387 | 
                + /**  | 
            |
| 388 | 
                + * Factory method to create a new ViewDragHelper.  | 
            |
| 389 | 
                + *  | 
            |
| 390 | 
                + * @param forParent Parent view to monitor  | 
            |
| 391 | 
                + * @param sensitivity Multiplier for how sensitive the helper should be  | 
            |
| 392 | 
                + * about detecting the start of a drag. Larger values are more  | 
            |
| 393 | 
                + * sensitive. 1.0f is normal.  | 
            |
| 394 | 
                + * @param cb Callback to provide information and receive events  | 
            |
| 395 | 
                + * @return a new ViewDragHelper instance  | 
            |
| 396 | 
                + */  | 
            |
| 397 | 
                +    public static ViewDragHelper create(ViewGroup forParent, float sensitivity, Callback cb) {
               | 
            |
| 398 | 
                + final ViewDragHelper helper = create(forParent, cb);  | 
            |
| 399 | 
                + helper.mTouchSlop = (int) (helper.mTouchSlop * (1 / sensitivity));  | 
            |
| 400 | 
                + return helper;  | 
            |
| 401 | 
                + }  | 
            |
| 402 | 
                +  | 
            |
| 403 | 
                + /**  | 
            |
| 404 | 
                + * Apps should use ViewDragHelper.create() to get a new instance. This will  | 
            |
| 405 | 
                + * allow VDH to use internal compatibility implementations for different  | 
            |
| 406 | 
                + * platform versions.  | 
            |
| 407 | 
                + *  | 
            |
| 408 | 
                + * @param context Context to initialize config-dependent params from  | 
            |
| 409 | 
                + * @param forParent Parent view to monitor  | 
            |
| 410 | 
                + */  | 
            |
| 411 | 
                +    private ViewDragHelper(Context context, ViewGroup forParent, Callback cb) {
               | 
            |
| 412 | 
                +        if (forParent == null) {
               | 
            |
| 413 | 
                +            throw new IllegalArgumentException("Parent view may not be null");
               | 
            |
| 414 | 
                + }  | 
            |
| 415 | 
                +        if (cb == null) {
               | 
            |
| 416 | 
                +            throw new IllegalArgumentException("Callback may not be null");
               | 
            |
| 417 | 
                + }  | 
            |
| 418 | 
                +  | 
            |
| 419 | 
                + mParentView = forParent;  | 
            |
| 420 | 
                + mCallback = cb;  | 
            |
| 421 | 
                +  | 
            |
| 422 | 
                + final ViewConfiguration vc = ViewConfiguration.get(context);  | 
            |
| 423 | 
                + final float density = context.getResources().getDisplayMetrics().density;  | 
            |
| 424 | 
                + mEdgeSize = (int) (EDGE_SIZE * density + 0.5f);  | 
            |
| 425 | 
                +  | 
            |
| 426 | 
                + mTouchSlop = vc.getScaledTouchSlop();  | 
            |
| 427 | 
                + mMaxVelocity = vc.getScaledMaximumFlingVelocity();  | 
            |
| 428 | 
                + mMinVelocity = vc.getScaledMinimumFlingVelocity();  | 
            |
| 429 | 
                + mScroller = ScrollerCompat.create(context, sInterpolator);  | 
            |
| 430 | 
                + }  | 
            |
| 431 | 
                +  | 
            |
| 432 | 
                + /**  | 
            |
| 433 | 
                + * Sets the sensitivity of the dragger.  | 
            |
| 434 | 
                + *  | 
            |
| 435 | 
                + * @param context The application context.  | 
            |
| 436 | 
                + * @param sensitivity value between 0 and 1, the final value for touchSlop =  | 
            |
| 437 | 
                + * ViewConfiguration.getScaledTouchSlop * (1 / s);  | 
            |
| 438 | 
                + */  | 
            |
| 439 | 
                +    public void setSensitivity(Context context, float sensitivity) {
               | 
            |
| 440 | 
                + float s = Math.max(0f, Math.min(1.0f, sensitivity));  | 
            |
| 441 | 
                + ViewConfiguration viewConfiguration = ViewConfiguration.get(context);  | 
            |
| 442 | 
                + mTouchSlop = (int) (viewConfiguration.getScaledTouchSlop() * (1 / s));  | 
            |
| 443 | 
                + }  | 
            |
| 444 | 
                +  | 
            |
| 445 | 
                + /**  | 
            |
| 446 | 
                + * Set the minimum velocity that will be detected as having a magnitude  | 
            |
| 447 | 
                + * greater than zero in pixels per second. Callback methods accepting a  | 
            |
| 448 | 
                + * velocity will be clamped appropriately.  | 
            |
| 449 | 
                + *  | 
            |
| 450 | 
                + * @param minVel minimum velocity to detect  | 
            |
| 451 | 
                + */  | 
            |
| 452 | 
                +    public void setMinVelocity(float minVel) {
               | 
            |
| 453 | 
                + mMinVelocity = minVel;  | 
            |
| 454 | 
                + }  | 
            |
| 455 | 
                +  | 
            |
| 456 | 
                + /**  | 
            |
| 457 | 
                + * Set the max velocity that will be detected as having a magnitude  | 
            |
| 458 | 
                + * greater than zero in pixels per second. Callback methods accepting a  | 
            |
| 459 | 
                + * velocity will be clamped appropriately.  | 
            |
| 460 | 
                + *  | 
            |
| 461 | 
                + * @param maxVel max velocity to detect  | 
            |
| 462 | 
                + */  | 
            |
| 463 | 
                +    public void setMaxVelocity(float maxVel) {
               | 
            |
| 464 | 
                + mMaxVelocity = maxVel;  | 
            |
| 465 | 
                + }  | 
            |
| 466 | 
                +  | 
            |
| 467 | 
                + /**  | 
            |
| 468 | 
                + * Return the currently configured minimum velocity. Any flings with a  | 
            |
| 469 | 
                + * magnitude less than this value in pixels per second. Callback methods  | 
            |
| 470 | 
                + * accepting a velocity will receive zero as a velocity value if the real  | 
            |
| 471 | 
                + * detected velocity was below this threshold.  | 
            |
| 472 | 
                + *  | 
            |
| 473 | 
                + * @return the minimum velocity that will be detected  | 
            |
| 474 | 
                + */  | 
            |
| 475 | 
                +    public float getMinVelocity() {
               | 
            |
| 476 | 
                + return mMinVelocity;  | 
            |
| 477 | 
                + }  | 
            |
| 478 | 
                +  | 
            |
| 479 | 
                + /**  | 
            |
| 480 | 
                + * Retrieve the current drag state of this helper. This will return one of  | 
            |
| 481 | 
                +     * {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}.
               | 
            |
| 482 | 
                + *  | 
            |
| 483 | 
                + * @return The current drag state  | 
            |
| 484 | 
                + */  | 
            |
| 485 | 
                +    public int getViewDragState() {
               | 
            |
| 486 | 
                + return mDragState;  | 
            |
| 487 | 
                + }  | 
            |
| 488 | 
                +  | 
            |
| 489 | 
                + /**  | 
            |
| 490 | 
                + * Enable edge tracking for the selected edges of the parent view. The  | 
            |
| 491 | 
                + * callback's  | 
            |
| 492 | 
                +     * {@link me.imid.swipebacklayout.lib.ViewDragHelper.Callback#onEdgeTouched(int, int)}
               | 
            |
| 493 | 
                + * and  | 
            |
| 494 | 
                +     * {@link me.imid.swipebacklayout.lib.ViewDragHelper.Callback#onEdgeDragStarted(int, int)}
               | 
            |
| 495 | 
                + * methods will only be invoked for edges for which edge tracking has been  | 
            |
| 496 | 
                + * enabled.  | 
            |
| 497 | 
                + *  | 
            |
| 498 | 
                + * @param edgeFlags Combination of edge flags describing the edges to watch  | 
            |
| 499 | 
                + * @see #EDGE_LEFT  | 
            |
| 500 | 
                + * @see #EDGE_TOP  | 
            |
| 501 | 
                + * @see #EDGE_RIGHT  | 
            |
| 502 | 
                + * @see #EDGE_BOTTOM  | 
            |
| 503 | 
                + */  | 
            |
| 504 | 
                +    public void setEdgeTrackingEnabled(int edgeFlags) {
               | 
            |
| 505 | 
                + mTrackingEdges = edgeFlags;  | 
            |
| 506 | 
                + }  | 
            |
| 507 | 
                +  | 
            |
| 508 | 
                + /**  | 
            |
| 509 | 
                + * Return the size of an edge. This is the range in pixels along the edges  | 
            |
| 510 | 
                + * of this view that will actively detect edge touches or drags if edge  | 
            |
| 511 | 
                + * tracking is enabled.  | 
            |
| 512 | 
                + *  | 
            |
| 513 | 
                + * @return The size of an edge in pixels  | 
            |
| 514 | 
                + * @see #setEdgeTrackingEnabled(int)  | 
            |
| 515 | 
                + */  | 
            |
| 516 | 
                +    public int getEdgeSize() {
               | 
            |
| 517 | 
                + return mEdgeSize;  | 
            |
| 518 | 
                + }  | 
            |
| 519 | 
                +  | 
            |
| 520 | 
                + /**  | 
            |
| 521 | 
                + * Set the size of an edge. This is the range in pixels along the edges of  | 
            |
| 522 | 
                + * this view that will actively detect edge touches or drags if edge  | 
            |
| 523 | 
                + * tracking is enabled.  | 
            |
| 524 | 
                + *  | 
            |
| 525 | 
                + * @param size The size of an edge in pixels  | 
            |
| 526 | 
                + */  | 
            |
| 527 | 
                +    public void setEdgeSize(int size) {
               | 
            |
| 528 | 
                + mEdgeSize = size;  | 
            |
| 529 | 
                + }  | 
            |
| 530 | 
                +  | 
            |
| 531 | 
                + /**  | 
            |
| 532 | 
                + * Capture a specific child view for dragging within the parent. The  | 
            |
| 533 | 
                + * callback will be notified but  | 
            |
| 534 | 
                +     * {@link me.imid.swipebacklayout.lib.ViewDragHelper.Callback#tryCaptureView(View, int)}
               | 
            |
| 535 | 
                + * will not be asked permission to capture this view.  | 
            |
| 536 | 
                + *  | 
            |
| 537 | 
                + * @param childView Child view to capture  | 
            |
| 538 | 
                + * @param activePointerId ID of the pointer that is dragging the captured  | 
            |
| 539 | 
                + * child view  | 
            |
| 540 | 
                + */  | 
            |
| 541 | 
                +    public void captureChildView(View childView, int activePointerId) {
               | 
            |
| 542 | 
                +        if (childView.getParent() != mParentView) {
               | 
            |
| 543 | 
                +            throw new IllegalArgumentException("captureChildView: parameter must be a descendant "
               | 
            |
| 544 | 
                +                    + "of the ViewDragHelper's tracked parent view (" + mParentView + ")");
               | 
            |
| 545 | 
                + }  | 
            |
| 546 | 
                +  | 
            |
| 547 | 
                + mCapturedView = childView;  | 
            |
| 548 | 
                + mActivePointerId = activePointerId;  | 
            |
| 549 | 
                + mCallback.onViewCaptured(childView, activePointerId);  | 
            |
| 550 | 
                + setDragState(STATE_DRAGGING);  | 
            |
| 551 | 
                + }  | 
            |
| 552 | 
                +  | 
            |
| 553 | 
                + /**  | 
            |
| 554 | 
                + * @return The currently captured view, or null if no view has been  | 
            |
| 555 | 
                + * captured.  | 
            |
| 556 | 
                + */  | 
            |
| 557 | 
                +    public View getCapturedView() {
               | 
            |
| 558 | 
                + return mCapturedView;  | 
            |
| 559 | 
                + }  | 
            |
| 560 | 
                +  | 
            |
| 561 | 
                + /**  | 
            |
| 562 | 
                + * @return The ID of the pointer currently dragging the captured view, or  | 
            |
| 563 | 
                +     * {@link #INVALID_POINTER}.
               | 
            |
| 564 | 
                + */  | 
            |
| 565 | 
                +    public int getActivePointerId() {
               | 
            |
| 566 | 
                + return mActivePointerId;  | 
            |
| 567 | 
                + }  | 
            |
| 568 | 
                +  | 
            |
| 569 | 
                + /**  | 
            |
| 570 | 
                + * @return The minimum distance in pixels that the user must travel to  | 
            |
| 571 | 
                + * initiate a drag  | 
            |
| 572 | 
                + */  | 
            |
| 573 | 
                +    public int getTouchSlop() {
               | 
            |
| 574 | 
                + return mTouchSlop;  | 
            |
| 575 | 
                + }  | 
            |
| 576 | 
                +  | 
            |
| 577 | 
                + /**  | 
            |
| 578 | 
                + * The result of a call to this method is equivalent to  | 
            |
| 579 | 
                +     * {@link #processTouchEvent(MotionEvent)} receiving an
               | 
            |
| 580 | 
                + * ACTION_CANCEL event.  | 
            |
| 581 | 
                + */  | 
            |
| 582 | 
                +    public void cancel() {
               | 
            |
| 583 | 
                + mActivePointerId = INVALID_POINTER;  | 
            |
| 584 | 
                + clearMotionHistory();  | 
            |
| 585 | 
                +  | 
            |
| 586 | 
                +        if (mVelocityTracker != null) {
               | 
            |
| 587 | 
                + mVelocityTracker.recycle();  | 
            |
| 588 | 
                + mVelocityTracker = null;  | 
            |
| 589 | 
                + }  | 
            |
| 590 | 
                + }  | 
            |
| 591 | 
                +  | 
            |
| 592 | 
                + /**  | 
            |
| 593 | 
                +     * {@link #cancel()}, but also abort all motion in progress and snap to the
               | 
            |
| 594 | 
                + * end of any animation.  | 
            |
| 595 | 
                + */  | 
            |
| 596 | 
                +    public void abort() {
               | 
            |
| 597 | 
                + cancel();  | 
            |
| 598 | 
                +        if (mDragState == STATE_SETTLING) {
               | 
            |
| 599 | 
                + final int oldX = mScroller.getCurrX();  | 
            |
| 600 | 
                + final int oldY = mScroller.getCurrY();  | 
            |
| 601 | 
                + mScroller.abortAnimation();  | 
            |
| 602 | 
                + final int newX = mScroller.getCurrX();  | 
            |
| 603 | 
                + final int newY = mScroller.getCurrY();  | 
            |
| 604 | 
                + mCallback.onViewPositionChanged(mCapturedView, newX, newY, newX - oldX, newY - oldY);  | 
            |
| 605 | 
                + }  | 
            |
| 606 | 
                + setDragState(STATE_IDLE);  | 
            |
| 607 | 
                + }  | 
            |
| 608 | 
                +  | 
            |
| 609 | 
                + /**  | 
            |
| 610 | 
                + * Animate the view <code>child</code> to the given (left, top) position. If  | 
            |
| 611 | 
                + * this method returns true, the caller should invoke  | 
            |
| 612 | 
                +     * {@link #continueSettling(boolean)} on each subsequent frame to continue
               | 
            |
| 613 | 
                + * the motion until it returns false. If this method returns false there is  | 
            |
| 614 | 
                + * no further work to do to complete the movement.  | 
            |
| 615 | 
                + * <p>  | 
            |
| 616 | 
                + * This operation does not count as a capture event, though  | 
            |
| 617 | 
                +     * {@link #getCapturedView()} will still report the sliding view while the
               | 
            |
| 618 | 
                + * slide is in progress.  | 
            |
| 619 | 
                + * </p>  | 
            |
| 620 | 
                + *  | 
            |
| 621 | 
                + * @param child Child view to capture and animate  | 
            |
| 622 | 
                + * @param finalLeft Final left position of child  | 
            |
| 623 | 
                + * @param finalTop Final top position of child  | 
            |
| 624 | 
                + * @return true if animation should continue through  | 
            |
| 625 | 
                +     * {@link #continueSettling(boolean)} calls
               | 
            |
| 626 | 
                + */  | 
            |
| 627 | 
                +    public boolean smoothSlideViewTo(View child, int finalLeft, int finalTop) {
               | 
            |
| 628 | 
                + mCapturedView = child;  | 
            |
| 629 | 
                + mActivePointerId = INVALID_POINTER;  | 
            |
| 630 | 
                +  | 
            |
| 631 | 
                + return forceSettleCapturedViewAt(finalLeft, finalTop, 0, 0);  | 
            |
| 632 | 
                + }  | 
            |
| 633 | 
                +  | 
            |
| 634 | 
                + /**  | 
            |
| 635 | 
                + * Settle the captured view at the given (left, top) position. The  | 
            |
| 636 | 
                + * appropriate velocity from prior motion will be taken into account. If  | 
            |
| 637 | 
                + * this method returns true, the caller should invoke  | 
            |
| 638 | 
                +     * {@link #continueSettling(boolean)} on each subsequent frame to continue
               | 
            |
| 639 | 
                + * the motion until it returns false. If this method returns false there is  | 
            |
| 640 | 
                + * no further work to do to complete the movement.  | 
            |
| 641 | 
                + *  | 
            |
| 642 | 
                + * @param finalLeft Settled left edge position for the captured view  | 
            |
| 643 | 
                + * @param finalTop Settled top edge position for the captured view  | 
            |
| 644 | 
                + * @return true if animation should continue through  | 
            |
| 645 | 
                +     * {@link #continueSettling(boolean)} calls
               | 
            |
| 646 | 
                + */  | 
            |
| 647 | 
                +    public boolean settleCapturedViewAt(int finalLeft, int finalTop) {
               | 
            |
| 648 | 
                +        if (!mReleaseInProgress) {
               | 
            |
| 649 | 
                +            throw new IllegalStateException("Cannot settleCapturedViewAt outside of a call to "
               | 
            |
| 650 | 
                + + "Callback#onViewReleased");  | 
            |
| 651 | 
                + }  | 
            |
| 652 | 
                +  | 
            |
| 653 | 
                + return forceSettleCapturedViewAt(finalLeft, finalTop,  | 
            |
| 654 | 
                + (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),  | 
            |
| 655 | 
                + (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId));  | 
            |
| 656 | 
                + }  | 
            |
| 657 | 
                +  | 
            |
| 658 | 
                + /**  | 
            |
| 659 | 
                + * Settle the captured view at the given (left, top) position.  | 
            |
| 660 | 
                + *  | 
            |
| 661 | 
                + * @param finalLeft Target left position for the captured view  | 
            |
| 662 | 
                + * @param finalTop Target top position for the captured view  | 
            |
| 663 | 
                + * @param xvel Horizontal velocity  | 
            |
| 664 | 
                + * @param yvel Vertical velocity  | 
            |
| 665 | 
                + * @return true if animation should continue through  | 
            |
| 666 | 
                +     * {@link #continueSettling(boolean)} calls
               | 
            |
| 667 | 
                + */  | 
            |
| 668 | 
                +    private boolean forceSettleCapturedViewAt(int finalLeft, int finalTop, int xvel, int yvel) {
               | 
            |
| 669 | 
                + final int startLeft = mCapturedView.getLeft();  | 
            |
| 670 | 
                + final int startTop = mCapturedView.getTop();  | 
            |
| 671 | 
                + final int dx = finalLeft - startLeft;  | 
            |
| 672 | 
                + final int dy = finalTop - startTop;  | 
            |
| 673 | 
                +  | 
            |
| 674 | 
                +        if (dx == 0 && dy == 0) {
               | 
            |
| 675 | 
                + // Nothing to do. Send callbacks, be done.  | 
            |
| 676 | 
                + mScroller.abortAnimation();  | 
            |
| 677 | 
                + setDragState(STATE_IDLE);  | 
            |
| 678 | 
                + return false;  | 
            |
| 679 | 
                + }  | 
            |
| 680 | 
                +  | 
            |
| 681 | 
                + final int duration = computeSettleDuration(mCapturedView, dx, dy, xvel, yvel);  | 
            |
| 682 | 
                + mScroller.startScroll(startLeft, startTop, dx, dy, duration);  | 
            |
| 683 | 
                +  | 
            |
| 684 | 
                + setDragState(STATE_SETTLING);  | 
            |
| 685 | 
                + return true;  | 
            |
| 686 | 
                + }  | 
            |
| 687 | 
                +  | 
            |
| 688 | 
                +    private int computeSettleDuration(View child, int dx, int dy, int xvel, int yvel) {
               | 
            |
| 689 | 
                + xvel = clampMag(xvel, (int) mMinVelocity, (int) mMaxVelocity);  | 
            |
| 690 | 
                + yvel = clampMag(yvel, (int) mMinVelocity, (int) mMaxVelocity);  | 
            |
| 691 | 
                + final int absDx = Math.abs(dx);  | 
            |
| 692 | 
                + final int absDy = Math.abs(dy);  | 
            |
| 693 | 
                + final int absXVel = Math.abs(xvel);  | 
            |
| 694 | 
                + final int absYVel = Math.abs(yvel);  | 
            |
| 695 | 
                + final int addedVel = absXVel + absYVel;  | 
            |
| 696 | 
                + final int addedDistance = absDx + absDy;  | 
            |
| 697 | 
                +  | 
            |
| 698 | 
                + final float xweight = xvel != 0 ? (float) absXVel / addedVel : (float) absDx  | 
            |
| 699 | 
                + / addedDistance;  | 
            |
| 700 | 
                + final float yweight = yvel != 0 ? (float) absYVel / addedVel : (float) absDy  | 
            |
| 701 | 
                + / addedDistance;  | 
            |
| 702 | 
                +  | 
            |
| 703 | 
                + int xduration = computeAxisDuration(dx, xvel, mCallback.getViewHorizontalDragRange(child));  | 
            |
| 704 | 
                + int yduration = computeAxisDuration(dy, yvel, mCallback.getViewVerticalDragRange(child));  | 
            |
| 705 | 
                +  | 
            |
| 706 | 
                + return (int) (xduration * xweight + yduration * yweight);  | 
            |
| 707 | 
                + }  | 
            |
| 708 | 
                +  | 
            |
| 709 | 
                +    private int computeAxisDuration(int delta, int velocity, int motionRange) {
               | 
            |
| 710 | 
                +        if (delta == 0) {
               | 
            |
| 711 | 
                + return 0;  | 
            |
| 712 | 
                + }  | 
            |
| 713 | 
                +  | 
            |
| 714 | 
                + final int width = mParentView.getWidth();  | 
            |
| 715 | 
                + final int halfWidth = width / 2;  | 
            |
| 716 | 
                + final float distanceRatio = Math.min(1f, (float) Math.abs(delta) / width);  | 
            |
| 717 | 
                + final float distance = halfWidth + halfWidth  | 
            |
| 718 | 
                + * distanceInfluenceForSnapDuration(distanceRatio);  | 
            |
| 719 | 
                +  | 
            |
| 720 | 
                + int duration;  | 
            |
| 721 | 
                + velocity = Math.abs(velocity);  | 
            |
| 722 | 
                +        if (velocity > 0) {
               | 
            |
| 723 | 
                + duration = 4 * Math.round(1000 * Math.abs(distance / velocity));  | 
            |
| 724 | 
                +        } else {
               | 
            |
| 725 | 
                + final float range = (float) Math.abs(delta) / motionRange;  | 
            |
| 726 | 
                + duration = (int) ((range + 1) * BASE_SETTLE_DURATION);  | 
            |
| 727 | 
                + }  | 
            |
| 728 | 
                + return Math.min(duration, MAX_SETTLE_DURATION);  | 
            |
| 729 | 
                + }  | 
            |
| 730 | 
                +  | 
            |
| 731 | 
                + /**  | 
            |
| 732 | 
                + * Clamp the magnitude of value for absMin and absMax. If the value is below  | 
            |
| 733 | 
                + * the minimum, it will be clamped to zero. If the value is above the  | 
            |
| 734 | 
                + * maximum, it will be clamped to the maximum.  | 
            |
| 735 | 
                + *  | 
            |
| 736 | 
                + * @param value Value to clamp  | 
            |
| 737 | 
                + * @param absMin Absolute value of the minimum significant value to return  | 
            |
| 738 | 
                + * @param absMax Absolute value of the maximum value to return  | 
            |
| 739 | 
                + * @return The clamped value with the same sign as <code>value</code>  | 
            |
| 740 | 
                + */  | 
            |
| 741 | 
                +    private int clampMag(int value, int absMin, int absMax) {
               | 
            |
| 742 | 
                + final int absValue = Math.abs(value);  | 
            |
| 743 | 
                + if (absValue < absMin)  | 
            |
| 744 | 
                + return 0;  | 
            |
| 745 | 
                + if (absValue > absMax)  | 
            |
| 746 | 
                + return value > 0 ? absMax : -absMax;  | 
            |
| 747 | 
                + return value;  | 
            |
| 748 | 
                + }  | 
            |
| 749 | 
                +  | 
            |
| 750 | 
                + /**  | 
            |
| 751 | 
                + * Clamp the magnitude of value for absMin and absMax. If the value is below  | 
            |
| 752 | 
                + * the minimum, it will be clamped to zero. If the value is above the  | 
            |
| 753 | 
                + * maximum, it will be clamped to the maximum.  | 
            |
| 754 | 
                + *  | 
            |
| 755 | 
                + * @param value Value to clamp  | 
            |
| 756 | 
                + * @param absMin Absolute value of the minimum significant value to return  | 
            |
| 757 | 
                + * @param absMax Absolute value of the maximum value to return  | 
            |
| 758 | 
                + * @return The clamped value with the same sign as <code>value</code>  | 
            |
| 759 | 
                + */  | 
            |
| 760 | 
                +    private float clampMag(float value, float absMin, float absMax) {
               | 
            |
| 761 | 
                + final float absValue = Math.abs(value);  | 
            |
| 762 | 
                + if (absValue < absMin)  | 
            |
| 763 | 
                + return 0;  | 
            |
| 764 | 
                + if (absValue > absMax)  | 
            |
| 765 | 
                + return value > 0 ? absMax : -absMax;  | 
            |
| 766 | 
                + return value;  | 
            |
| 767 | 
                + }  | 
            |
| 768 | 
                +  | 
            |
| 769 | 
                +    private float distanceInfluenceForSnapDuration(float f) {
               | 
            |
| 770 | 
                + f -= 0.5f; // center the values about 0.  | 
            |
| 771 | 
                + f *= 0.3f * Math.PI / 2.0f;  | 
            |
| 772 | 
                + return (float) Math.sin(f);  | 
            |
| 773 | 
                + }  | 
            |
| 774 | 
                +  | 
            |
| 775 | 
                + /**  | 
            |
| 776 | 
                + * Settle the captured view based on standard free-moving fling behavior.  | 
            |
| 777 | 
                +     * The caller should invoke {@link #continueSettling(boolean)} on each
               | 
            |
| 778 | 
                + * subsequent frame to continue the motion until it returns false.  | 
            |
| 779 | 
                + *  | 
            |
| 780 | 
                + * @param minLeft Minimum X position for the view's left edge  | 
            |
| 781 | 
                + * @param minTop Minimum Y position for the view's top edge  | 
            |
| 782 | 
                + * @param maxLeft Maximum X position for the view's left edge  | 
            |
| 783 | 
                + * @param maxTop Maximum Y position for the view's top edge  | 
            |
| 784 | 
                + */  | 
            |
| 785 | 
                +    public void flingCapturedView(int minLeft, int minTop, int maxLeft, int maxTop) {
               | 
            |
| 786 | 
                +        if (!mReleaseInProgress) {
               | 
            |
| 787 | 
                +            throw new IllegalStateException("Cannot flingCapturedView outside of a call to "
               | 
            |
| 788 | 
                + + "Callback#onViewReleased");  | 
            |
| 789 | 
                + }  | 
            |
| 790 | 
                +  | 
            |
| 791 | 
                + mScroller.fling(mCapturedView.getLeft(), mCapturedView.getTop(),  | 
            |
| 792 | 
                + (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),  | 
            |
| 793 | 
                + (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId),  | 
            |
| 794 | 
                + minLeft, maxLeft, minTop, maxTop);  | 
            |
| 795 | 
                +  | 
            |
| 796 | 
                + setDragState(STATE_SETTLING);  | 
            |
| 797 | 
                + }  | 
            |
| 798 | 
                +  | 
            |
| 799 | 
                + /**  | 
            |
| 800 | 
                + * Move the captured settling view by the appropriate amount for the current  | 
            |
| 801 | 
                + * time. If <code>continueSettling</code> returns true, the caller should  | 
            |
| 802 | 
                + * call it again on the next frame to continue.  | 
            |
| 803 | 
                + *  | 
            |
| 804 | 
                + * @param deferCallbacks true if state callbacks should be deferred via  | 
            |
| 805 | 
                + * posted message. Set this to true if you are calling this  | 
            |
| 806 | 
                +     *                       method from {@link View#computeScroll()} or
               | 
            |
| 807 | 
                + * similar methods invoked as part of layout or drawing.  | 
            |
| 808 | 
                + * @return true if settle is still in progress  | 
            |
| 809 | 
                + */  | 
            |
| 810 | 
                +    public boolean continueSettling(boolean deferCallbacks) {
               | 
            |
| 811 | 
                +        if (mDragState == STATE_SETTLING) {
               | 
            |
| 812 | 
                + boolean keepGoing = mScroller.computeScrollOffset();  | 
            |
| 813 | 
                + final int x = mScroller.getCurrX();  | 
            |
| 814 | 
                + final int y = mScroller.getCurrY();  | 
            |
| 815 | 
                + final int dx = x - mCapturedView.getLeft();  | 
            |
| 816 | 
                + final int dy = y - mCapturedView.getTop();  | 
            |
| 817 | 
                +  | 
            |
| 818 | 
                +            if (dx != 0) {
               | 
            |
| 819 | 
                + mCapturedView.offsetLeftAndRight(dx);  | 
            |
| 820 | 
                + }  | 
            |
| 821 | 
                +            if (dy != 0) {
               | 
            |
| 822 | 
                + mCapturedView.offsetTopAndBottom(dy);  | 
            |
| 823 | 
                + }  | 
            |
| 824 | 
                +  | 
            |
| 825 | 
                +            if (dx != 0 || dy != 0) {
               | 
            |
| 826 | 
                + mCallback.onViewPositionChanged(mCapturedView, x, y, dx, dy);  | 
            |
| 827 | 
                + }  | 
            |
| 828 | 
                +  | 
            |
| 829 | 
                +            if (keepGoing && x == mScroller.getFinalX() && y == mScroller.getFinalY()) {
               | 
            |
| 830 | 
                + // Close enough. The interpolator/scroller might think we're  | 
            |
| 831 | 
                + // still moving  | 
            |
| 832 | 
                + // but the user sure doesn't.  | 
            |
| 833 | 
                + mScroller.abortAnimation();  | 
            |
| 834 | 
                + keepGoing = mScroller.isFinished();  | 
            |
| 835 | 
                + }  | 
            |
| 836 | 
                +  | 
            |
| 837 | 
                +            if (!keepGoing) {
               | 
            |
| 838 | 
                +                if (deferCallbacks) {
               | 
            |
| 839 | 
                + mParentView.post(mSetIdleRunnable);  | 
            |
| 840 | 
                +                } else {
               | 
            |
| 841 | 
                + setDragState(STATE_IDLE);  | 
            |
| 842 | 
                + }  | 
            |
| 843 | 
                + }  | 
            |
| 844 | 
                + }  | 
            |
| 845 | 
                +  | 
            |
| 846 | 
                + return mDragState == STATE_SETTLING;  | 
            |
| 847 | 
                + }  | 
            |
| 848 | 
                +  | 
            |
| 849 | 
                + /**  | 
            |
| 850 | 
                + * Like all callback events this must happen on the UI thread, but release  | 
            |
| 851 | 
                + * involves some extra semantics. During a release (mReleaseInProgress) is  | 
            |
| 852 | 
                +     * the only time it is valid to call {@link #settleCapturedViewAt(int, int)}
               | 
            |
| 853 | 
                +     * or {@link #flingCapturedView(int, int, int, int)}.
               | 
            |
| 854 | 
                + */  | 
            |
| 855 | 
                +    private void dispatchViewReleased(float xvel, float yvel) {
               | 
            |
| 856 | 
                + mReleaseInProgress = true;  | 
            |
| 857 | 
                + mCallback.onViewReleased(mCapturedView, xvel, yvel);  | 
            |
| 858 | 
                + mReleaseInProgress = false;  | 
            |
| 859 | 
                +  | 
            |
| 860 | 
                +        if (mDragState == STATE_DRAGGING) {
               | 
            |
| 861 | 
                + // onViewReleased didn't call a method that would have changed this.  | 
            |
| 862 | 
                + // Go idle.  | 
            |
| 863 | 
                + setDragState(STATE_IDLE);  | 
            |
| 864 | 
                + }  | 
            |
| 865 | 
                + }  | 
            |
| 866 | 
                +  | 
            |
| 867 | 
                +    private void clearMotionHistory() {
               | 
            |
| 868 | 
                +        if (mInitialMotionX == null) {
               | 
            |
| 869 | 
                + return;  | 
            |
| 870 | 
                + }  | 
            |
| 871 | 
                + Arrays.fill(mInitialMotionX, 0);  | 
            |
| 872 | 
                + Arrays.fill(mInitialMotionY, 0);  | 
            |
| 873 | 
                + Arrays.fill(mLastMotionX, 0);  | 
            |
| 874 | 
                + Arrays.fill(mLastMotionY, 0);  | 
            |
| 875 | 
                + Arrays.fill(mInitialEdgeTouched, 0);  | 
            |
| 876 | 
                + Arrays.fill(mEdgeDragsInProgress, 0);  | 
            |
| 877 | 
                + Arrays.fill(mEdgeDragsLocked, 0);  | 
            |
| 878 | 
                + mPointersDown = 0;  | 
            |
| 879 | 
                + }  | 
            |
| 880 | 
                +  | 
            |
| 881 | 
                +    private void clearMotionHistory(int pointerId) {
               | 
            |
| 882 | 
                +        if (mInitialMotionX == null) {
               | 
            |
| 883 | 
                + return;  | 
            |
| 884 | 
                + }  | 
            |
| 885 | 
                + mInitialMotionX[pointerId] = 0;  | 
            |
| 886 | 
                + mInitialMotionY[pointerId] = 0;  | 
            |
| 887 | 
                + mLastMotionX[pointerId] = 0;  | 
            |
| 888 | 
                + mLastMotionY[pointerId] = 0;  | 
            |
| 889 | 
                + mInitialEdgeTouched[pointerId] = 0;  | 
            |
| 890 | 
                + mEdgeDragsInProgress[pointerId] = 0;  | 
            |
| 891 | 
                + mEdgeDragsLocked[pointerId] = 0;  | 
            |
| 892 | 
                + mPointersDown &= ~(1 << pointerId);  | 
            |
| 893 | 
                + }  | 
            |
| 894 | 
                +  | 
            |
| 895 | 
                +    private void ensureMotionHistorySizeForId(int pointerId) {
               | 
            |
| 896 | 
                +        if (mInitialMotionX == null || mInitialMotionX.length <= pointerId) {
               | 
            |
| 897 | 
                + float[] imx = new float[pointerId + 1];  | 
            |
| 898 | 
                + float[] imy = new float[pointerId + 1];  | 
            |
| 899 | 
                + float[] lmx = new float[pointerId + 1];  | 
            |
| 900 | 
                + float[] lmy = new float[pointerId + 1];  | 
            |
| 901 | 
                + int[] iit = new int[pointerId + 1];  | 
            |
| 902 | 
                + int[] edip = new int[pointerId + 1];  | 
            |
| 903 | 
                + int[] edl = new int[pointerId + 1];  | 
            |
| 904 | 
                +  | 
            |
| 905 | 
                +            if (mInitialMotionX != null) {
               | 
            |
| 906 | 
                + System.arraycopy(mInitialMotionX, 0, imx, 0, mInitialMotionX.length);  | 
            |
| 907 | 
                + System.arraycopy(mInitialMotionY, 0, imy, 0, mInitialMotionY.length);  | 
            |
| 908 | 
                + System.arraycopy(mLastMotionX, 0, lmx, 0, mLastMotionX.length);  | 
            |
| 909 | 
                + System.arraycopy(mLastMotionY, 0, lmy, 0, mLastMotionY.length);  | 
            |
| 910 | 
                + System.arraycopy(mInitialEdgeTouched, 0, iit, 0, mInitialEdgeTouched.length);  | 
            |
| 911 | 
                + System.arraycopy(mEdgeDragsInProgress, 0, edip, 0, mEdgeDragsInProgress.length);  | 
            |
| 912 | 
                + System.arraycopy(mEdgeDragsLocked, 0, edl, 0, mEdgeDragsLocked.length);  | 
            |
| 913 | 
                + }  | 
            |
| 914 | 
                +  | 
            |
| 915 | 
                + mInitialMotionX = imx;  | 
            |
| 916 | 
                + mInitialMotionY = imy;  | 
            |
| 917 | 
                + mLastMotionX = lmx;  | 
            |
| 918 | 
                + mLastMotionY = lmy;  | 
            |
| 919 | 
                + mInitialEdgeTouched = iit;  | 
            |
| 920 | 
                + mEdgeDragsInProgress = edip;  | 
            |
| 921 | 
                + mEdgeDragsLocked = edl;  | 
            |
| 922 | 
                + }  | 
            |
| 923 | 
                + }  | 
            |
| 924 | 
                +  | 
            |
| 925 | 
                +    private void saveInitialMotion(float x, float y, int pointerId) {
               | 
            |
| 926 | 
                + ensureMotionHistorySizeForId(pointerId);  | 
            |
| 927 | 
                + mInitialMotionX[pointerId] = mLastMotionX[pointerId] = x;  | 
            |
| 928 | 
                + mInitialMotionY[pointerId] = mLastMotionY[pointerId] = y;  | 
            |
| 929 | 
                + mInitialEdgeTouched[pointerId] = getEdgeTouched((int) x, (int) y);  | 
            |
| 930 | 
                + mPointersDown |= 1 << pointerId;  | 
            |
| 931 | 
                + }  | 
            |
| 932 | 
                +  | 
            |
| 933 | 
                +    private void saveLastMotion(MotionEvent ev) {
               | 
            |
| 934 | 
                + final int pointerCount = MotionEventCompat.getPointerCount(ev);  | 
            |
| 935 | 
                +        for (int i = 0; i < pointerCount; i++) {
               | 
            |
| 936 | 
                + final int pointerId = MotionEventCompat.getPointerId(ev, i);  | 
            |
| 937 | 
                + final float x = MotionEventCompat.getX(ev, i);  | 
            |
| 938 | 
                + final float y = MotionEventCompat.getY(ev, i);  | 
            |
| 939 | 
                + mLastMotionX[pointerId] = x;  | 
            |
| 940 | 
                + mLastMotionY[pointerId] = y;  | 
            |
| 941 | 
                + }  | 
            |
| 942 | 
                + }  | 
            |
| 943 | 
                +  | 
            |
| 944 | 
                + /**  | 
            |
| 945 | 
                + * Check if the given pointer ID represents a pointer that is currently down  | 
            |
| 946 | 
                + * (to the best of the ViewDragHelper's knowledge).  | 
            |
| 947 | 
                + * <p>  | 
            |
| 948 | 
                + * The state used to report this information is populated by the methods  | 
            |
| 949 | 
                +     * {@link #shouldInterceptTouchEvent(MotionEvent)} or
               | 
            |
| 950 | 
                +     * {@link #processTouchEvent(MotionEvent)}. If one of these
               | 
            |
| 951 | 
                + * methods has not been called for all relevant MotionEvents to track, the  | 
            |
| 952 | 
                + * information reported by this method may be stale or incorrect.  | 
            |
| 953 | 
                + * </p>  | 
            |
| 954 | 
                + *  | 
            |
| 955 | 
                + * @param pointerId pointer ID to check; corresponds to IDs provided by  | 
            |
| 956 | 
                + * MotionEvent  | 
            |
| 957 | 
                + * @return true if the pointer with the given ID is still down  | 
            |
| 958 | 
                + */  | 
            |
| 959 | 
                +    public boolean isPointerDown(int pointerId) {
               | 
            |
| 960 | 
                + return (mPointersDown & 1 << pointerId) != 0;  | 
            |
| 961 | 
                + }  | 
            |
| 962 | 
                +  | 
            |
| 963 | 
                +    void setDragState(int state) {
               | 
            |
| 964 | 
                +        if (mDragState != state) {
               | 
            |
| 965 | 
                + mDragState = state;  | 
            |
| 966 | 
                + mCallback.onViewDragStateChanged(state);  | 
            |
| 967 | 
                +            if (state == STATE_IDLE) {
               | 
            |
| 968 | 
                + mCapturedView = null;  | 
            |
| 969 | 
                + }  | 
            |
| 970 | 
                + }  | 
            |
| 971 | 
                + }  | 
            |
| 972 | 
                +  | 
            |
| 973 | 
                + /**  | 
            |
| 974 | 
                + * Attempt to capture the view with the given pointer ID. The callback will  | 
            |
| 975 | 
                + * be involved. This will put us into the "dragging" state. If we've already  | 
            |
| 976 | 
                + * captured this view with this pointer this method will immediately return  | 
            |
| 977 | 
                + * true without consulting the callback.  | 
            |
| 978 | 
                + *  | 
            |
| 979 | 
                + * @param toCapture View to capture  | 
            |
| 980 | 
                + * @param pointerId Pointer to capture with  | 
            |
| 981 | 
                + * @return true if capture was successful  | 
            |
| 982 | 
                + */  | 
            |
| 983 | 
                +    boolean tryCaptureViewForDrag(View toCapture, int pointerId) {
               | 
            |
| 984 | 
                +        if (toCapture == mCapturedView && mActivePointerId == pointerId) {
               | 
            |
| 985 | 
                + // Already done!  | 
            |
| 986 | 
                + return true;  | 
            |
| 987 | 
                + }  | 
            |
| 988 | 
                +        if (toCapture != null && mCallback.tryCaptureView(toCapture, pointerId)) {
               | 
            |
| 989 | 
                + mActivePointerId = pointerId;  | 
            |
| 990 | 
                + captureChildView(toCapture, pointerId);  | 
            |
| 991 | 
                + return true;  | 
            |
| 992 | 
                + }  | 
            |
| 993 | 
                + return false;  | 
            |
| 994 | 
                + }  | 
            |
| 995 | 
                +  | 
            |
| 996 | 
                + /**  | 
            |
| 997 | 
                + * Tests scrollability within child views of v given a delta of dx.  | 
            |
| 998 | 
                + *  | 
            |
| 999 | 
                + * @param v View to test for horizontal scrollability  | 
            |
| 1000 | 
                + * @param checkV Whether the view v passed should itself be checked for  | 
            |
| 1001 | 
                + * scrollability (true), or just its children (false).  | 
            |
| 1002 | 
                + * @param dx Delta scrolled in pixels along the X axis  | 
            |
| 1003 | 
                + * @param dy Delta scrolled in pixels along the Y axis  | 
            |
| 1004 | 
                + * @param x X coordinate of the active touch point  | 
            |
| 1005 | 
                + * @param y Y coordinate of the active touch point  | 
            |
| 1006 | 
                + * @return true if child views of v can be scrolled by delta of dx.  | 
            |
| 1007 | 
                + */  | 
            |
| 1008 | 
                +    protected boolean canScroll(View v, boolean checkV, int dx, int dy, int x, int y) {
               | 
            |
| 1009 | 
                +        if (v instanceof ViewGroup) {
               | 
            |
| 1010 | 
                + final ViewGroup group = (ViewGroup) v;  | 
            |
| 1011 | 
                + final int scrollX = v.getScrollX();  | 
            |
| 1012 | 
                + final int scrollY = v.getScrollY();  | 
            |
| 1013 | 
                + final int count = group.getChildCount();  | 
            |
| 1014 | 
                + // Count backwards - let topmost views consume scroll distance  | 
            |
| 1015 | 
                + // first.  | 
            |
| 1016 | 
                +            for (int i = count - 1; i >= 0; i--) {
               | 
            |
| 1017 | 
                + // TODO: Add versioned support here for transformed views.  | 
            |
| 1018 | 
                + // This will not work for transformed views in Honeycomb+  | 
            |
| 1019 | 
                + final View child = group.getChildAt(i);  | 
            |
| 1020 | 
                + if (x + scrollX >= child.getLeft()  | 
            |
| 1021 | 
                + && x + scrollX < child.getRight()  | 
            |
| 1022 | 
                + && y + scrollY >= child.getTop()  | 
            |
| 1023 | 
                + && y + scrollY < child.getBottom()  | 
            |
| 1024 | 
                + && canScroll(child, true, dx, dy, x + scrollX - child.getLeft(), y  | 
            |
| 1025 | 
                +                        + scrollY - child.getTop())) {
               | 
            |
| 1026 | 
                + return true;  | 
            |
| 1027 | 
                + }  | 
            |
| 1028 | 
                + }  | 
            |
| 1029 | 
                + }  | 
            |
| 1030 | 
                +  | 
            |
| 1031 | 
                + return checkV  | 
            |
| 1032 | 
                + && (ViewCompat.canScrollHorizontally(v, -dx) || ViewCompat.canScrollVertically(v,  | 
            |
| 1033 | 
                + -dy));  | 
            |
| 1034 | 
                + }  | 
            |
| 1035 | 
                +  | 
            |
| 1036 | 
                + /**  | 
            |
| 1037 | 
                + * Check if this event as provided to the parent view's  | 
            |
| 1038 | 
                + * onInterceptTouchEvent should cause the parent to intercept the touch  | 
            |
| 1039 | 
                + * event stream.  | 
            |
| 1040 | 
                + *  | 
            |
| 1041 | 
                + * @param ev MotionEvent provided to onInterceptTouchEvent  | 
            |
| 1042 | 
                + * @return true if the parent view should return true from  | 
            |
| 1043 | 
                + * onInterceptTouchEvent  | 
            |
| 1044 | 
                + */  | 
            |
| 1045 | 
                +    public boolean shouldInterceptTouchEvent(MotionEvent ev) {
               | 
            |
| 1046 | 
                + final int action = MotionEventCompat.getActionMasked(ev);  | 
            |
| 1047 | 
                + final int actionIndex = MotionEventCompat.getActionIndex(ev);  | 
            |
| 1048 | 
                +  | 
            |
| 1049 | 
                +        if (action == MotionEvent.ACTION_DOWN) {
               | 
            |
| 1050 | 
                + // Reset things for a new event stream, just in case we didn't get  | 
            |
| 1051 | 
                + // the whole previous stream.  | 
            |
| 1052 | 
                + cancel();  | 
            |
| 1053 | 
                + }  | 
            |
| 1054 | 
                +  | 
            |
| 1055 | 
                +        if (mVelocityTracker == null) {
               | 
            |
| 1056 | 
                + mVelocityTracker = VelocityTracker.obtain();  | 
            |
| 1057 | 
                + }  | 
            |
| 1058 | 
                + mVelocityTracker.addMovement(ev);  | 
            |
| 1059 | 
                +  | 
            |
| 1060 | 
                +        switch (action) {
               | 
            |
| 1061 | 
                +            case MotionEvent.ACTION_DOWN: {
               | 
            |
| 1062 | 
                + final float x = ev.getX();  | 
            |
| 1063 | 
                + final float y = ev.getY();  | 
            |
| 1064 | 
                + final int pointerId = MotionEventCompat.getPointerId(ev, 0);  | 
            |
| 1065 | 
                + saveInitialMotion(x, y, pointerId);  | 
            |
| 1066 | 
                +  | 
            |
| 1067 | 
                + final View toCapture = findTopChildUnder((int) x, (int) y);  | 
            |
| 1068 | 
                +  | 
            |
| 1069 | 
                + // Catch a settling view if possible.  | 
            |
| 1070 | 
                +                if (toCapture == mCapturedView && mDragState == STATE_SETTLING) {
               | 
            |
| 1071 | 
                + tryCaptureViewForDrag(toCapture, pointerId);  | 
            |
| 1072 | 
                + }  | 
            |
| 1073 | 
                +  | 
            |
| 1074 | 
                + final int edgesTouched = mInitialEdgeTouched[pointerId];  | 
            |
| 1075 | 
                +                if ((edgesTouched & mTrackingEdges) != 0) {
               | 
            |
| 1076 | 
                + mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);  | 
            |
| 1077 | 
                + }  | 
            |
| 1078 | 
                + break;  | 
            |
| 1079 | 
                + }  | 
            |
| 1080 | 
                +  | 
            |
| 1081 | 
                +            case MotionEventCompat.ACTION_POINTER_DOWN: {
               | 
            |
| 1082 | 
                + final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);  | 
            |
| 1083 | 
                + final float x = MotionEventCompat.getX(ev, actionIndex);  | 
            |
| 1084 | 
                + final float y = MotionEventCompat.getY(ev, actionIndex);  | 
            |
| 1085 | 
                +  | 
            |
| 1086 | 
                + saveInitialMotion(x, y, pointerId);  | 
            |
| 1087 | 
                +  | 
            |
| 1088 | 
                + // A ViewDragHelper can only manipulate one view at a time.  | 
            |
| 1089 | 
                +                if (mDragState == STATE_IDLE) {
               | 
            |
| 1090 | 
                + final int edgesTouched = mInitialEdgeTouched[pointerId];  | 
            |
| 1091 | 
                +                    if ((edgesTouched & mTrackingEdges) != 0) {
               | 
            |
| 1092 | 
                + mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);  | 
            |
| 1093 | 
                + }  | 
            |
| 1094 | 
                +                } else if (mDragState == STATE_SETTLING) {
               | 
            |
| 1095 | 
                + // Catch a settling view if possible.  | 
            |
| 1096 | 
                + final View toCapture = findTopChildUnder((int) x, (int) y);  | 
            |
| 1097 | 
                +                    if (toCapture == mCapturedView) {
               | 
            |
| 1098 | 
                + tryCaptureViewForDrag(toCapture, pointerId);  | 
            |
| 1099 | 
                + }  | 
            |
| 1100 | 
                + }  | 
            |
| 1101 | 
                + break;  | 
            |
| 1102 | 
                + }  | 
            |
| 1103 | 
                +  | 
            |
| 1104 | 
                +            case MotionEvent.ACTION_MOVE: {
               | 
            |
| 1105 | 
                + // First to cross a touch slop over a draggable view wins. Also  | 
            |
| 1106 | 
                + // report edge drags.  | 
            |
| 1107 | 
                + final int pointerCount = MotionEventCompat.getPointerCount(ev);  | 
            |
| 1108 | 
                +                for (int i = 0; i < pointerCount; i++) {
               | 
            |
| 1109 | 
                + final int pointerId = MotionEventCompat.getPointerId(ev, i);  | 
            |
| 1110 | 
                + final float x = MotionEventCompat.getX(ev, i);  | 
            |
| 1111 | 
                + final float y = MotionEventCompat.getY(ev, i);  | 
            |
| 1112 | 
                + final float dx = x - mInitialMotionX[pointerId];  | 
            |
| 1113 | 
                + final float dy = y - mInitialMotionY[pointerId];  | 
            |
| 1114 | 
                +  | 
            |
| 1115 | 
                + reportNewEdgeDrags(dx, dy, pointerId);  | 
            |
| 1116 | 
                +                    if (mDragState == STATE_DRAGGING) {
               | 
            |
| 1117 | 
                + // Callback might have started an edge drag  | 
            |
| 1118 | 
                + break;  | 
            |
| 1119 | 
                + }  | 
            |
| 1120 | 
                +  | 
            |
| 1121 | 
                + final View toCapture = findTopChildUnder((int) x, (int) y);  | 
            |
| 1122 | 
                + if (toCapture != null && checkTouchSlop(toCapture, dx, dy)  | 
            |
| 1123 | 
                +                            && tryCaptureViewForDrag(toCapture, pointerId)) {
               | 
            |
| 1124 | 
                + break;  | 
            |
| 1125 | 
                + }  | 
            |
| 1126 | 
                + }  | 
            |
| 1127 | 
                + saveLastMotion(ev);  | 
            |
| 1128 | 
                + break;  | 
            |
| 1129 | 
                + }  | 
            |
| 1130 | 
                +  | 
            |
| 1131 | 
                +            case MotionEventCompat.ACTION_POINTER_UP: {
               | 
            |
| 1132 | 
                + final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);  | 
            |
| 1133 | 
                + clearMotionHistory(pointerId);  | 
            |
| 1134 | 
                + break;  | 
            |
| 1135 | 
                + }  | 
            |
| 1136 | 
                +  | 
            |
| 1137 | 
                + case MotionEvent.ACTION_UP:  | 
            |
| 1138 | 
                +            case MotionEvent.ACTION_CANCEL: {
               | 
            |
| 1139 | 
                + cancel();  | 
            |
| 1140 | 
                + break;  | 
            |
| 1141 | 
                + }  | 
            |
| 1142 | 
                + }  | 
            |
| 1143 | 
                +  | 
            |
| 1144 | 
                + return mDragState == STATE_DRAGGING;  | 
            |
| 1145 | 
                + }  | 
            |
| 1146 | 
                +  | 
            |
| 1147 | 
                + /**  | 
            |
| 1148 | 
                + * Process a touch event received by the parent view. This method will  | 
            |
| 1149 | 
                + * dispatch callback events as needed before returning. The parent view's  | 
            |
| 1150 | 
                + * onTouchEvent implementation should call this.  | 
            |
| 1151 | 
                + *  | 
            |
| 1152 | 
                + * @param ev The touch event received by the parent view  | 
            |
| 1153 | 
                + */  | 
            |
| 1154 | 
                +    public void processTouchEvent(MotionEvent ev) {
               | 
            |
| 1155 | 
                + final int action = MotionEventCompat.getActionMasked(ev);  | 
            |
| 1156 | 
                + final int actionIndex = MotionEventCompat.getActionIndex(ev);  | 
            |
| 1157 | 
                +  | 
            |
| 1158 | 
                +        if (action == MotionEvent.ACTION_DOWN) {
               | 
            |
| 1159 | 
                + // Reset things for a new event stream, just in case we didn't get  | 
            |
| 1160 | 
                + // the whole previous stream.  | 
            |
| 1161 | 
                + cancel();  | 
            |
| 1162 | 
                + }  | 
            |
| 1163 | 
                +  | 
            |
| 1164 | 
                +        if (mVelocityTracker == null) {
               | 
            |
| 1165 | 
                + mVelocityTracker = VelocityTracker.obtain();  | 
            |
| 1166 | 
                + }  | 
            |
| 1167 | 
                + mVelocityTracker.addMovement(ev);  | 
            |
| 1168 | 
                +  | 
            |
| 1169 | 
                +        switch (action) {
               | 
            |
| 1170 | 
                +            case MotionEvent.ACTION_DOWN: {
               | 
            |
| 1171 | 
                + final float x = ev.getX();  | 
            |
| 1172 | 
                + final float y = ev.getY();  | 
            |
| 1173 | 
                + final int pointerId = MotionEventCompat.getPointerId(ev, 0);  | 
            |
| 1174 | 
                + final View toCapture = findTopChildUnder((int) x, (int) y);  | 
            |
| 1175 | 
                +  | 
            |
| 1176 | 
                + saveInitialMotion(x, y, pointerId);  | 
            |
| 1177 | 
                +  | 
            |
| 1178 | 
                + // Since the parent is already directly processing this touch  | 
            |
| 1179 | 
                + // event,  | 
            |
| 1180 | 
                + // there is no reason to delay for a slop before dragging.  | 
            |
| 1181 | 
                + // Start immediately if possible.  | 
            |
| 1182 | 
                + tryCaptureViewForDrag(toCapture, pointerId);  | 
            |
| 1183 | 
                +  | 
            |
| 1184 | 
                + final int edgesTouched = mInitialEdgeTouched[pointerId];  | 
            |
| 1185 | 
                +                if ((edgesTouched & mTrackingEdges) != 0) {
               | 
            |
| 1186 | 
                + mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);  | 
            |
| 1187 | 
                + }  | 
            |
| 1188 | 
                + break;  | 
            |
| 1189 | 
                + }  | 
            |
| 1190 | 
                +  | 
            |
| 1191 | 
                +            case MotionEventCompat.ACTION_POINTER_DOWN: {
               | 
            |
| 1192 | 
                + final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);  | 
            |
| 1193 | 
                + final float x = MotionEventCompat.getX(ev, actionIndex);  | 
            |
| 1194 | 
                + final float y = MotionEventCompat.getY(ev, actionIndex);  | 
            |
| 1195 | 
                +  | 
            |
| 1196 | 
                + saveInitialMotion(x, y, pointerId);  | 
            |
| 1197 | 
                +  | 
            |
| 1198 | 
                + // A ViewDragHelper can only manipulate one view at a time.  | 
            |
| 1199 | 
                +                if (mDragState == STATE_IDLE) {
               | 
            |
| 1200 | 
                + // If we're idle we can do anything! Treat it like a normal  | 
            |
| 1201 | 
                + // down event.  | 
            |
| 1202 | 
                +  | 
            |
| 1203 | 
                + final View toCapture = findTopChildUnder((int) x, (int) y);  | 
            |
| 1204 | 
                + tryCaptureViewForDrag(toCapture, pointerId);  | 
            |
| 1205 | 
                +  | 
            |
| 1206 | 
                + final int edgesTouched = mInitialEdgeTouched[pointerId];  | 
            |
| 1207 | 
                +                    if ((edgesTouched & mTrackingEdges) != 0) {
               | 
            |
| 1208 | 
                + mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);  | 
            |
| 1209 | 
                + }  | 
            |
| 1210 | 
                +                } else if (isCapturedViewUnder((int) x, (int) y)) {
               | 
            |
| 1211 | 
                + // We're still tracking a captured view. If the same view is  | 
            |
| 1212 | 
                + // under this  | 
            |
| 1213 | 
                + // point, we'll swap to controlling it with this pointer  | 
            |
| 1214 | 
                + // instead.  | 
            |
| 1215 | 
                + // (This will still work if we're "catching" a settling  | 
            |
| 1216 | 
                + // view.)  | 
            |
| 1217 | 
                +  | 
            |
| 1218 | 
                + tryCaptureViewForDrag(mCapturedView, pointerId);  | 
            |
| 1219 | 
                + }  | 
            |
| 1220 | 
                + break;  | 
            |
| 1221 | 
                + }  | 
            |
| 1222 | 
                +  | 
            |
| 1223 | 
                +            case MotionEvent.ACTION_MOVE: {
               | 
            |
| 1224 | 
                +                if (mDragState == STATE_DRAGGING) {
               | 
            |
| 1225 | 
                + final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId);  | 
            |
| 1226 | 
                + final float x = MotionEventCompat.getX(ev, index);  | 
            |
| 1227 | 
                + final float y = MotionEventCompat.getY(ev, index);  | 
            |
| 1228 | 
                + final int idx = (int) (x - mLastMotionX[mActivePointerId]);  | 
            |
| 1229 | 
                + final int idy = (int) (y - mLastMotionY[mActivePointerId]);  | 
            |
| 1230 | 
                +  | 
            |
| 1231 | 
                + dragTo(mCapturedView.getLeft() + idx, mCapturedView.getTop() + idy, idx, idy);  | 
            |
| 1232 | 
                +  | 
            |
| 1233 | 
                + saveLastMotion(ev);  | 
            |
| 1234 | 
                +                } else {
               | 
            |
| 1235 | 
                + // Check to see if any pointer is now over a draggable view.  | 
            |
| 1236 | 
                + final int pointerCount = MotionEventCompat.getPointerCount(ev);  | 
            |
| 1237 | 
                +                    for (int i = 0; i < pointerCount; i++) {
               | 
            |
| 1238 | 
                + final int pointerId = MotionEventCompat.getPointerId(ev, i);  | 
            |
| 1239 | 
                + final float x = MotionEventCompat.getX(ev, i);  | 
            |
| 1240 | 
                + final float y = MotionEventCompat.getY(ev, i);  | 
            |
| 1241 | 
                + final float dx = x - mInitialMotionX[pointerId];  | 
            |
| 1242 | 
                + final float dy = y - mInitialMotionY[pointerId];  | 
            |
| 1243 | 
                +  | 
            |
| 1244 | 
                + reportNewEdgeDrags(dx, dy, pointerId);  | 
            |
| 1245 | 
                +                        if (mDragState == STATE_DRAGGING) {
               | 
            |
| 1246 | 
                + // Callback might have started an edge drag.  | 
            |
| 1247 | 
                + break;  | 
            |
| 1248 | 
                + }  | 
            |
| 1249 | 
                +  | 
            |
| 1250 | 
                + final View toCapture = findTopChildUnder((int) x, (int) y);  | 
            |
| 1251 | 
                + if (checkTouchSlop(toCapture, dx, dy)  | 
            |
| 1252 | 
                +                                && tryCaptureViewForDrag(toCapture, pointerId)) {
               | 
            |
| 1253 | 
                + break;  | 
            |
| 1254 | 
                + }  | 
            |
| 1255 | 
                + }  | 
            |
| 1256 | 
                + saveLastMotion(ev);  | 
            |
| 1257 | 
                + }  | 
            |
| 1258 | 
                + break;  | 
            |
| 1259 | 
                + }  | 
            |
| 1260 | 
                +  | 
            |
| 1261 | 
                +            case MotionEventCompat.ACTION_POINTER_UP: {
               | 
            |
| 1262 | 
                + final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);  | 
            |
| 1263 | 
                +                if (mDragState == STATE_DRAGGING && pointerId == mActivePointerId) {
               | 
            |
| 1264 | 
                + // Try to find another pointer that's still holding on to  | 
            |
| 1265 | 
                + // the captured view.  | 
            |
| 1266 | 
                + int newActivePointer = INVALID_POINTER;  | 
            |
| 1267 | 
                + final int pointerCount = MotionEventCompat.getPointerCount(ev);  | 
            |
| 1268 | 
                +                    for (int i = 0; i < pointerCount; i++) {
               | 
            |
| 1269 | 
                + final int id = MotionEventCompat.getPointerId(ev, i);  | 
            |
| 1270 | 
                +                        if (id == mActivePointerId) {
               | 
            |
| 1271 | 
                + // This one's going away, skip.  | 
            |
| 1272 | 
                + continue;  | 
            |
| 1273 | 
                + }  | 
            |
| 1274 | 
                +  | 
            |
| 1275 | 
                + final float x = MotionEventCompat.getX(ev, i);  | 
            |
| 1276 | 
                + final float y = MotionEventCompat.getY(ev, i);  | 
            |
| 1277 | 
                + if (findTopChildUnder((int) x, (int) y) == mCapturedView  | 
            |
| 1278 | 
                +                                && tryCaptureViewForDrag(mCapturedView, id)) {
               | 
            |
| 1279 | 
                + newActivePointer = mActivePointerId;  | 
            |
| 1280 | 
                + break;  | 
            |
| 1281 | 
                + }  | 
            |
| 1282 | 
                + }  | 
            |
| 1283 | 
                +  | 
            |
| 1284 | 
                +                    if (newActivePointer == INVALID_POINTER) {
               | 
            |
| 1285 | 
                + // We didn't find another pointer still touching the  | 
            |
| 1286 | 
                + // view, release it.  | 
            |
| 1287 | 
                + releaseViewForPointerUp();  | 
            |
| 1288 | 
                + }  | 
            |
| 1289 | 
                + }  | 
            |
| 1290 | 
                + clearMotionHistory(pointerId);  | 
            |
| 1291 | 
                + break;  | 
            |
| 1292 | 
                + }  | 
            |
| 1293 | 
                +  | 
            |
| 1294 | 
                +            case MotionEvent.ACTION_UP: {
               | 
            |
| 1295 | 
                +                if (mDragState == STATE_DRAGGING) {
               | 
            |
| 1296 | 
                + releaseViewForPointerUp();  | 
            |
| 1297 | 
                + }  | 
            |
| 1298 | 
                + cancel();  | 
            |
| 1299 | 
                + break;  | 
            |
| 1300 | 
                + }  | 
            |
| 1301 | 
                +  | 
            |
| 1302 | 
                +            case MotionEvent.ACTION_CANCEL: {
               | 
            |
| 1303 | 
                +                if (mDragState == STATE_DRAGGING) {
               | 
            |
| 1304 | 
                + dispatchViewReleased(0, 0);  | 
            |
| 1305 | 
                + }  | 
            |
| 1306 | 
                + cancel();  | 
            |
| 1307 | 
                + break;  | 
            |
| 1308 | 
                + }  | 
            |
| 1309 | 
                + }  | 
            |
| 1310 | 
                + }  | 
            |
| 1311 | 
                +  | 
            |
| 1312 | 
                +    private void reportNewEdgeDrags(float dx, float dy, int pointerId) {
               | 
            |
| 1313 | 
                + int dragsStarted = 0;  | 
            |
| 1314 | 
                +        if (checkNewEdgeDrag(dx, dy, pointerId, EDGE_LEFT)) {
               | 
            |
| 1315 | 
                + dragsStarted |= EDGE_LEFT;  | 
            |
| 1316 | 
                + }  | 
            |
| 1317 | 
                +        if (checkNewEdgeDrag(dy, dx, pointerId, EDGE_TOP)) {
               | 
            |
| 1318 | 
                + dragsStarted |= EDGE_TOP;  | 
            |
| 1319 | 
                + }  | 
            |
| 1320 | 
                +        if (checkNewEdgeDrag(dx, dy, pointerId, EDGE_RIGHT)) {
               | 
            |
| 1321 | 
                + dragsStarted |= EDGE_RIGHT;  | 
            |
| 1322 | 
                + }  | 
            |
| 1323 | 
                +        if (checkNewEdgeDrag(dy, dx, pointerId, EDGE_BOTTOM)) {
               | 
            |
| 1324 | 
                + dragsStarted |= EDGE_BOTTOM;  | 
            |
| 1325 | 
                + }  | 
            |
| 1326 | 
                +  | 
            |
| 1327 | 
                +        if (dragsStarted != 0) {
               | 
            |
| 1328 | 
                + mEdgeDragsInProgress[pointerId] |= dragsStarted;  | 
            |
| 1329 | 
                + mCallback.onEdgeDragStarted(dragsStarted, pointerId);  | 
            |
| 1330 | 
                + }  | 
            |
| 1331 | 
                + }  | 
            |
| 1332 | 
                +  | 
            |
| 1333 | 
                +    private boolean checkNewEdgeDrag(float delta, float odelta, int pointerId, int edge) {
               | 
            |
| 1334 | 
                + final float absDelta = Math.abs(delta);  | 
            |
| 1335 | 
                + final float absODelta = Math.abs(odelta);  | 
            |
| 1336 | 
                +  | 
            |
| 1337 | 
                + if ((mInitialEdgeTouched[pointerId] & edge) != edge || (mTrackingEdges & edge) == 0  | 
            |
| 1338 | 
                + || (mEdgeDragsLocked[pointerId] & edge) == edge  | 
            |
| 1339 | 
                + || (mEdgeDragsInProgress[pointerId] & edge) == edge  | 
            |
| 1340 | 
                +                || (absDelta <= mTouchSlop && absODelta <= mTouchSlop)) {
               | 
            |
| 1341 | 
                + return false;  | 
            |
| 1342 | 
                + }  | 
            |
| 1343 | 
                +        if (absDelta < absODelta * 0.5f && mCallback.onEdgeLock(edge)) {
               | 
            |
| 1344 | 
                + mEdgeDragsLocked[pointerId] |= edge;  | 
            |
| 1345 | 
                + return false;  | 
            |
| 1346 | 
                + }  | 
            |
| 1347 | 
                + return (mEdgeDragsInProgress[pointerId] & edge) == 0 && absDelta > mTouchSlop;  | 
            |
| 1348 | 
                + }  | 
            |
| 1349 | 
                +  | 
            |
| 1350 | 
                + /**  | 
            |
| 1351 | 
                + * Check if we've crossed a reasonable touch slop for the given child view.  | 
            |
| 1352 | 
                + * If the child cannot be dragged along the horizontal or vertical axis,  | 
            |
| 1353 | 
                + * motion along that axis will not count toward the slop check.  | 
            |
| 1354 | 
                + *  | 
            |
| 1355 | 
                + * @param child Child to check  | 
            |
| 1356 | 
                + * @param dx Motion since initial position along X axis  | 
            |
| 1357 | 
                + * @param dy Motion since initial position along Y axis  | 
            |
| 1358 | 
                + * @return true if the touch slop has been crossed  | 
            |
| 1359 | 
                + */  | 
            |
| 1360 | 
                +    private boolean checkTouchSlop(View child, float dx, float dy) {
               | 
            |
| 1361 | 
                +        if (child == null) {
               | 
            |
| 1362 | 
                + return false;  | 
            |
| 1363 | 
                + }  | 
            |
| 1364 | 
                + final boolean checkHorizontal = mCallback.getViewHorizontalDragRange(child) > 0;  | 
            |
| 1365 | 
                + final boolean checkVertical = mCallback.getViewVerticalDragRange(child) > 0;  | 
            |
| 1366 | 
                +  | 
            |
| 1367 | 
                +        if (checkHorizontal && checkVertical) {
               | 
            |
| 1368 | 
                + return dx * dx + dy * dy > mTouchSlop * mTouchSlop;  | 
            |
| 1369 | 
                +        } else if (checkHorizontal) {
               | 
            |
| 1370 | 
                + return Math.abs(dx) > mTouchSlop;  | 
            |
| 1371 | 
                +        } else if (checkVertical) {
               | 
            |
| 1372 | 
                + return Math.abs(dy) > mTouchSlop;  | 
            |
| 1373 | 
                + }  | 
            |
| 1374 | 
                + return false;  | 
            |
| 1375 | 
                + }  | 
            |
| 1376 | 
                +  | 
            |
| 1377 | 
                + /**  | 
            |
| 1378 | 
                + * Check if any pointer tracked in the current gesture has crossed the  | 
            |
| 1379 | 
                + * required slop threshold.  | 
            |
| 1380 | 
                + * <p>  | 
            |
| 1381 | 
                + * This depends on internal state populated by  | 
            |
| 1382 | 
                +     * {@link #shouldInterceptTouchEvent(MotionEvent)} or
               | 
            |
| 1383 | 
                +     * {@link #processTouchEvent(MotionEvent)}. You should only
               | 
            |
| 1384 | 
                + * rely on the results of this method after all currently available touch  | 
            |
| 1385 | 
                + * data has been provided to one of these two methods.  | 
            |
| 1386 | 
                + * </p>  | 
            |
| 1387 | 
                + *  | 
            |
| 1388 | 
                + * @param directions Combination of direction flags, see  | 
            |
| 1389 | 
                +     *                   {@link #DIRECTION_HORIZONTAL}, {@link #DIRECTION_VERTICAL},
               | 
            |
| 1390 | 
                +     *                   {@link #DIRECTION_ALL}
               | 
            |
| 1391 | 
                + * @return true if the slop threshold has been crossed, false otherwise  | 
            |
| 1392 | 
                + */  | 
            |
| 1393 | 
                +    public boolean checkTouchSlop(int directions) {
               | 
            |
| 1394 | 
                + final int count = mInitialMotionX.length;  | 
            |
| 1395 | 
                +        for (int i = 0; i < count; i++) {
               | 
            |
| 1396 | 
                +            if (checkTouchSlop(directions, i)) {
               | 
            |
| 1397 | 
                + return true;  | 
            |
| 1398 | 
                + }  | 
            |
| 1399 | 
                + }  | 
            |
| 1400 | 
                + return false;  | 
            |
| 1401 | 
                + }  | 
            |
| 1402 | 
                +  | 
            |
| 1403 | 
                + /**  | 
            |
| 1404 | 
                + * Check if the specified pointer tracked in the current gesture has crossed  | 
            |
| 1405 | 
                + * the required slop threshold.  | 
            |
| 1406 | 
                + * <p>  | 
            |
| 1407 | 
                + * This depends on internal state populated by  | 
            |
| 1408 | 
                +     * {@link #shouldInterceptTouchEvent(MotionEvent)} or
               | 
            |
| 1409 | 
                +     * {@link #processTouchEvent(MotionEvent)}. You should only
               | 
            |
| 1410 | 
                + * rely on the results of this method after all currently available touch  | 
            |
| 1411 | 
                + * data has been provided to one of these two methods.  | 
            |
| 1412 | 
                + * </p>  | 
            |
| 1413 | 
                + *  | 
            |
| 1414 | 
                + * @param directions Combination of direction flags, see  | 
            |
| 1415 | 
                +     *                   {@link #DIRECTION_HORIZONTAL}, {@link #DIRECTION_VERTICAL},
               | 
            |
| 1416 | 
                +     *                   {@link #DIRECTION_ALL}
               | 
            |
| 1417 | 
                + * @param pointerId ID of the pointer to slop check as specified by  | 
            |
| 1418 | 
                + * MotionEvent  | 
            |
| 1419 | 
                + * @return true if the slop threshold has been crossed, false otherwise  | 
            |
| 1420 | 
                + */  | 
            |
| 1421 | 
                +    public boolean checkTouchSlop(int directions, int pointerId) {
               | 
            |
| 1422 | 
                +        if (!isPointerDown(pointerId)) {
               | 
            |
| 1423 | 
                + return false;  | 
            |
| 1424 | 
                + }  | 
            |
| 1425 | 
                +  | 
            |
| 1426 | 
                + final boolean checkHorizontal = (directions & DIRECTION_HORIZONTAL) == DIRECTION_HORIZONTAL;  | 
            |
| 1427 | 
                + final boolean checkVertical = (directions & DIRECTION_VERTICAL) == DIRECTION_VERTICAL;  | 
            |
| 1428 | 
                +  | 
            |
| 1429 | 
                + final float dx = mLastMotionX[pointerId] - mInitialMotionX[pointerId];  | 
            |
| 1430 | 
                + final float dy = mLastMotionY[pointerId] - mInitialMotionY[pointerId];  | 
            |
| 1431 | 
                +  | 
            |
| 1432 | 
                +        if (checkHorizontal && checkVertical) {
               | 
            |
| 1433 | 
                + return dx * dx + dy * dy > mTouchSlop * mTouchSlop;  | 
            |
| 1434 | 
                +        } else if (checkHorizontal) {
               | 
            |
| 1435 | 
                + return Math.abs(dx) > mTouchSlop;  | 
            |
| 1436 | 
                +        } else if (checkVertical) {
               | 
            |
| 1437 | 
                + return Math.abs(dy) > mTouchSlop;  | 
            |
| 1438 | 
                + }  | 
            |
| 1439 | 
                + return false;  | 
            |
| 1440 | 
                + }  | 
            |
| 1441 | 
                +  | 
            |
| 1442 | 
                + /**  | 
            |
| 1443 | 
                + * Check if any of the edges specified were initially touched in the  | 
            |
| 1444 | 
                + * currently active gesture. If there is no currently active gesture this  | 
            |
| 1445 | 
                + * method will return false.  | 
            |
| 1446 | 
                + *  | 
            |
| 1447 | 
                + * @param edges Edges to check for an initial edge touch. See  | 
            |
| 1448 | 
                +     *              {@link #EDGE_LEFT}, {@link #EDGE_TOP}, {@link #EDGE_RIGHT},
               | 
            |
| 1449 | 
                +     *              {@link #EDGE_BOTTOM} and {@link #EDGE_ALL}
               | 
            |
| 1450 | 
                + * @return true if any of the edges specified were initially touched in the  | 
            |
| 1451 | 
                + * current gesture  | 
            |
| 1452 | 
                + */  | 
            |
| 1453 | 
                +    public boolean isEdgeTouched(int edges) {
               | 
            |
| 1454 | 
                + final int count = mInitialEdgeTouched.length;  | 
            |
| 1455 | 
                +        for (int i = 0; i < count; i++) {
               | 
            |
| 1456 | 
                +            if (isEdgeTouched(edges, i)) {
               | 
            |
| 1457 | 
                + return true;  | 
            |
| 1458 | 
                + }  | 
            |
| 1459 | 
                + }  | 
            |
| 1460 | 
                + return false;  | 
            |
| 1461 | 
                + }  | 
            |
| 1462 | 
                +  | 
            |
| 1463 | 
                + /**  | 
            |
| 1464 | 
                + * Check if any of the edges specified were initially touched by the pointer  | 
            |
| 1465 | 
                + * with the specified ID. If there is no currently active gesture or if  | 
            |
| 1466 | 
                + * there is no pointer with the given ID currently down this method will  | 
            |
| 1467 | 
                + * return false.  | 
            |
| 1468 | 
                + *  | 
            |
| 1469 | 
                + * @param edges Edges to check for an initial edge touch. See  | 
            |
| 1470 | 
                +     *              {@link #EDGE_LEFT}, {@link #EDGE_TOP}, {@link #EDGE_RIGHT},
               | 
            |
| 1471 | 
                +     *              {@link #EDGE_BOTTOM} and {@link #EDGE_ALL}
               | 
            |
| 1472 | 
                + * @return true if any of the edges specified were initially touched in the  | 
            |
| 1473 | 
                + * current gesture  | 
            |
| 1474 | 
                + */  | 
            |
| 1475 | 
                +    public boolean isEdgeTouched(int edges, int pointerId) {
               | 
            |
| 1476 | 
                + return isPointerDown(pointerId) && (mInitialEdgeTouched[pointerId] & edges) != 0;  | 
            |
| 1477 | 
                + }  | 
            |
| 1478 | 
                +  | 
            |
| 1479 | 
                +    private void releaseViewForPointerUp() {
               | 
            |
| 1480 | 
                + mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);  | 
            |
| 1481 | 
                + final float xvel = clampMag(  | 
            |
| 1482 | 
                + VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),  | 
            |
| 1483 | 
                + mMinVelocity, mMaxVelocity);  | 
            |
| 1484 | 
                + final float yvel = clampMag(  | 
            |
| 1485 | 
                + VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId),  | 
            |
| 1486 | 
                + mMinVelocity, mMaxVelocity);  | 
            |
| 1487 | 
                + dispatchViewReleased(xvel, yvel);  | 
            |
| 1488 | 
                + }  | 
            |
| 1489 | 
                +  | 
            |
| 1490 | 
                +    private void dragTo(int left, int top, int dx, int dy) {
               | 
            |
| 1491 | 
                + int clampedX = left;  | 
            |
| 1492 | 
                + int clampedY = top;  | 
            |
| 1493 | 
                + final int oldLeft = mCapturedView.getLeft();  | 
            |
| 1494 | 
                + final int oldTop = mCapturedView.getTop();  | 
            |
| 1495 | 
                +        if (dx != 0) {
               | 
            |
| 1496 | 
                + clampedX = mCallback.clampViewPositionHorizontal(mCapturedView, left, dx);  | 
            |
| 1497 | 
                + mCapturedView.offsetLeftAndRight(clampedX - oldLeft);  | 
            |
| 1498 | 
                + }  | 
            |
| 1499 | 
                +        if (dy != 0) {
               | 
            |
| 1500 | 
                + clampedY = mCallback.clampViewPositionVertical(mCapturedView, top, dy);  | 
            |
| 1501 | 
                + mCapturedView.offsetTopAndBottom(clampedY - oldTop);  | 
            |
| 1502 | 
                + }  | 
            |
| 1503 | 
                +  | 
            |
| 1504 | 
                +        if (dx != 0 || dy != 0) {
               | 
            |
| 1505 | 
                + final int clampedDx = clampedX - oldLeft;  | 
            |
| 1506 | 
                + final int clampedDy = clampedY - oldTop;  | 
            |
| 1507 | 
                + mCallback  | 
            |
| 1508 | 
                + .onViewPositionChanged(mCapturedView, clampedX, clampedY, clampedDx, clampedDy);  | 
            |
| 1509 | 
                + }  | 
            |
| 1510 | 
                + }  | 
            |
| 1511 | 
                +  | 
            |
| 1512 | 
                + /**  | 
            |
| 1513 | 
                + * Determine if the currently captured view is under the given point in the  | 
            |
| 1514 | 
                + * parent view's coordinate system. If there is no captured view this method  | 
            |
| 1515 | 
                + * will return false.  | 
            |
| 1516 | 
                + *  | 
            |
| 1517 | 
                + * @param x X position to test in the parent's coordinate system  | 
            |
| 1518 | 
                + * @param y Y position to test in the parent's coordinate system  | 
            |
| 1519 | 
                + * @return true if the captured view is under the given point, false  | 
            |
| 1520 | 
                + * otherwise  | 
            |
| 1521 | 
                + */  | 
            |
| 1522 | 
                +    public boolean isCapturedViewUnder(int x, int y) {
               | 
            |
| 1523 | 
                + return isViewUnder(mCapturedView, x, y);  | 
            |
| 1524 | 
                + }  | 
            |
| 1525 | 
                +  | 
            |
| 1526 | 
                + /**  | 
            |
| 1527 | 
                + * Determine if the supplied view is under the given point in the parent  | 
            |
| 1528 | 
                + * view's coordinate system.  | 
            |
| 1529 | 
                + *  | 
            |
| 1530 | 
                + * @param view Child view of the parent to hit test  | 
            |
| 1531 | 
                + * @param x X position to test in the parent's coordinate system  | 
            |
| 1532 | 
                + * @param y Y position to test in the parent's coordinate system  | 
            |
| 1533 | 
                + * @return true if the supplied view is under the given point, false  | 
            |
| 1534 | 
                + * otherwise  | 
            |
| 1535 | 
                + */  | 
            |
| 1536 | 
                +    public boolean isViewUnder(View view, int x, int y) {
               | 
            |
| 1537 | 
                +        if (view == null) {
               | 
            |
| 1538 | 
                + return false;  | 
            |
| 1539 | 
                + }  | 
            |
| 1540 | 
                + return x >= view.getLeft() && x < view.getRight() && y >= view.getTop()  | 
            |
| 1541 | 
                + && y < view.getBottom();  | 
            |
| 1542 | 
                + }  | 
            |
| 1543 | 
                +  | 
            |
| 1544 | 
                + /**  | 
            |
| 1545 | 
                + * Find the topmost child under the given point within the parent view's  | 
            |
| 1546 | 
                + * coordinate system. The child order is determined using  | 
            |
| 1547 | 
                +     * {@link me.imid.swipebacklayout.lib.ViewDragHelper.Callback#getOrderedChildIndex(int)}
               | 
            |
| 1548 | 
                + * .  | 
            |
| 1549 | 
                + *  | 
            |
| 1550 | 
                + * @param x X position to test in the parent's coordinate system  | 
            |
| 1551 | 
                + * @param y Y position to test in the parent's coordinate system  | 
            |
| 1552 | 
                + * @return The topmost child view under (x, y) or null if none found.  | 
            |
| 1553 | 
                + */  | 
            |
| 1554 | 
                +    public View findTopChildUnder(int x, int y) {
               | 
            |
| 1555 | 
                + final int childCount = mParentView.getChildCount();  | 
            |
| 1556 | 
                +        for (int i = childCount - 1; i >= 0; i--) {
               | 
            |
| 1557 | 
                + final View child = mParentView.getChildAt(mCallback.getOrderedChildIndex(i));  | 
            |
| 1558 | 
                + if (x >= child.getLeft() && x < child.getRight() && y >= child.getTop()  | 
            |
| 1559 | 
                +                    && y < child.getBottom()) {
               | 
            |
| 1560 | 
                + return child;  | 
            |
| 1561 | 
                + }  | 
            |
| 1562 | 
                + }  | 
            |
| 1563 | 
                + return null;  | 
            |
| 1564 | 
                + }  | 
            |
| 1565 | 
                +  | 
            |
| 1566 | 
                +    private int getEdgeTouched(int x, int y) {
               | 
            |
| 1567 | 
                + int result = 0;  | 
            |
| 1568 | 
                +  | 
            |
| 1569 | 
                + if (x < mParentView.getLeft() + mEdgeSize)  | 
            |
| 1570 | 
                + result = EDGE_LEFT;  | 
            |
| 1571 | 
                + if (y < mParentView.getTop() + mEdgeSize)  | 
            |
| 1572 | 
                + result = EDGE_TOP;  | 
            |
| 1573 | 
                + if (x > mParentView.getRight() - mEdgeSize)  | 
            |
| 1574 | 
                + result = EDGE_RIGHT;  | 
            |
| 1575 | 
                + if (y > mParentView.getBottom() - mEdgeSize)  | 
            |
| 1576 | 
                + result = EDGE_BOTTOM;  | 
            |
| 1577 | 
                +  | 
            |
| 1578 | 
                + return result;  | 
            |
| 1579 | 
                + }  | 
            |
| 1580 | 
                +}  | 
            
      
      
      
                @@ -0,0 +1,6 @@  | 
            ||
| 1 | 
                +<?xml version="1.0" encoding="utf-8"?>  | 
            |
| 2 | 
                +<com.android.views.swipebacklayout.SwipeBackLayout xmlns:android="http://schemas.android.com/apk/res/android"  | 
            |
| 3 | 
                + android:id="@+id/swipe"  | 
            |
| 4 | 
                + android:layout_width="match_parent"  | 
            |
| 5 | 
                + android:layout_height="match_parent" />  | 
            |
| 6 | 
                +  | 
            
                @@ -73,4 +73,18 @@  | 
            ||
| 73 | 73 | 
                </attr>  | 
            
| 74 | 74 | 
                </declare-styleable>  | 
            
| 75 | 75 | 
                 | 
            
| 76 | 
                + <declare-styleable name="SwipeBackLayout">  | 
            |
| 77 | 
                + <attr name="edge_size" format="dimension"/>  | 
            |
| 78 | 
                + <attr name="edge_flag">  | 
            |
| 79 | 
                + <enum name="left" value="0" />  | 
            |
| 80 | 
                + <enum name="right" value="1" />  | 
            |
| 81 | 
                + <enum name="bottom" value="2" />  | 
            |
| 82 | 
                + <enum name="all" value="3" />  | 
            |
| 83 | 
                + </attr>  | 
            |
| 84 | 
                + <attr name="shadow_left" format="reference"/>  | 
            |
| 85 | 
                + <attr name="shadow_right" format="reference"/>  | 
            |
| 86 | 
                + <attr name="shadow_bottom" format="reference"/>  | 
            |
| 87 | 
                + </declare-styleable>  | 
            |
| 88 | 
                +  | 
            |
| 89 | 
                + <attr name="SwipeBackLayoutStyle" format="reference"/>  | 
            |
| 76 | 90 | 
                </resources>  | 
            
                @@ -6,21 +6,12 @@  | 
            ||
| 6 | 6 | 
                <item name="android:background">@color/line_bg</item>  | 
            
| 7 | 7 | 
                <item name="android:layout_margin">2dp</item>  | 
            
| 8 | 8 | 
                </style>  | 
            
| 9 | 
                - <declare-styleable name="SwipeLayout">  | 
            |
| 10 | 
                - <attr name="drag_edge">  | 
            |
| 11 | 
                - <flag name="left" value="1" />  | 
            |
| 12 | 
                - <flag name="right" value="2" />  | 
            |
| 13 | 
                - <flag name="top" value="4" />  | 
            |
| 14 | 
                - <flag name="bottom" value="8" />  | 
            |
| 15 | 
                - </attr>  | 
            |
| 16 | 
                - <attr name="leftEdgeSwipeOffset" format="dimension" />  | 
            |
| 17 | 
                - <attr name="rightEdgeSwipeOffset" format="dimension" />  | 
            |
| 18 | 
                - <attr name="topEdgeSwipeOffset" format="dimension" />  | 
            |
| 19 | 
                - <attr name="bottomEdgeSwipeOffset" format="dimension" />  | 
            |
| 20 | 
                - <attr name="show_mode" format="enum">  | 
            |
| 21 | 
                - <enum name="lay_down" value="0" />  | 
            |
| 22 | 
                - <enum name="pull_out" value="1" />  | 
            |
| 23 | 
                - </attr>  | 
            |
| 24 | 
                - <attr name="clickToClose" format="boolean" />  | 
            |
| 25 | 
                - </declare-styleable>  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                + <style name="SwipeBackLayout">  | 
            |
| 11 | 
                + <item name="edge_size">50dip</item>  | 
            |
| 12 | 
                + <item name="shadow_left">@drawable/shadow_left</item>  | 
            |
| 13 | 
                + <item name="shadow_right">@drawable/shadow_right</item>  | 
            |
| 14 | 
                + <item name="shadow_bottom">@drawable/shadow_bottom</item>  | 
            |
| 15 | 
                + </style>  | 
            |
| 16 | 
                +  | 
            |
| 26 | 17 | 
                </resources>  |